@heyamiko/amiko-cli 0.9.0-beta.5 → 0.9.0-beta.7
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 +34 -30
- package/dist/index.js +118 -39
- package/package.json +1 -1
- package/skills/SKILL.md +29 -29
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @heyamiko/amiko-cli (v0.9.0-beta.
|
|
1
|
+
# @heyamiko/amiko-cli (v0.9.0-beta.7)
|
|
2
2
|
|
|
3
3
|
Manage wallets, credits, swaps, MPP marketplace services, and your Amiko twin (identity, documents, voice, avatar, friends, feed, Composio apps) from the terminal. Works for both human users and AI agents running on OpenClaw.
|
|
4
4
|
|
|
@@ -294,13 +294,13 @@ src/
|
|
|
294
294
|
│ ├── config.ts # config management
|
|
295
295
|
│ ├── update.ts # self-update
|
|
296
296
|
│ ├── accounts.ts # accounts, info (twin identity readout)
|
|
297
|
-
│ ├── twin.ts # twin
|
|
297
|
+
│ ├── twin.ts # twin update (name/description/public)
|
|
298
298
|
│ ├── docs.ts # RAG documents (list, upload, delete, presign)
|
|
299
|
-
│ ├── voice.ts # voice
|
|
300
|
-
│ ├── avatar.ts # avatar
|
|
299
|
+
│ ├── voice.ts # voice design, voice create, voice clone, voice reset
|
|
300
|
+
│ ├── avatar.ts # avatar update
|
|
301
301
|
│ ├── friends.ts # friends list, add, accept, remove
|
|
302
|
-
│ ├── feed.ts # feed, post
|
|
303
|
-
│ └── composio.ts # composio
|
|
302
|
+
│ ├── feed.ts # feed, post create, post comment
|
|
303
|
+
│ └── composio.ts # composio connect, composio disconnect
|
|
304
304
|
└── lib/
|
|
305
305
|
├── config.ts # defaults + resolved auth wrapper
|
|
306
306
|
├── agent-config.ts # .amiko.json reader + auth resolution
|
|
@@ -323,48 +323,48 @@ The CLI also manages the twin's identity, documents, voice, avatar, friends, fee
|
|
|
323
323
|
# Identity
|
|
324
324
|
amiko accounts # show resolved identity (mode, platform, user, twin, wallets)
|
|
325
325
|
amiko info # fetch twin info (name, description, voice, avatar, visibility)
|
|
326
|
-
amiko twin
|
|
327
|
-
amiko twin
|
|
328
|
-
amiko twin
|
|
326
|
+
amiko twin update --name "New Name"
|
|
327
|
+
amiko twin update --description "Bio"
|
|
328
|
+
amiko twin update --public true --yes # change public visibility (destructive)
|
|
329
329
|
|
|
330
330
|
# Documents (RAG)
|
|
331
|
-
amiko docs
|
|
332
|
-
amiko docs
|
|
333
|
-
amiko docs
|
|
334
|
-
amiko docs
|
|
331
|
+
amiko docs list # list
|
|
332
|
+
amiko docs upload ./notes.pdf # path, URL, or `- --stdin`
|
|
333
|
+
amiko docs delete <docId> --yes
|
|
334
|
+
amiko docs presign ./file.pdf # presigned S3 URL only
|
|
335
335
|
|
|
336
336
|
# Voice
|
|
337
|
-
amiko voice
|
|
338
|
-
amiko voice
|
|
339
|
-
amiko voice
|
|
340
|
-
amiko voice
|
|
337
|
+
amiko voice design --description "warm, low, male, confident, measured"
|
|
338
|
+
amiko voice create --sample <generated_voice_id>
|
|
339
|
+
amiko voice clone ./me.mp3
|
|
340
|
+
amiko voice reset --yes
|
|
341
341
|
|
|
342
342
|
# Avatar
|
|
343
|
-
amiko avatar
|
|
343
|
+
amiko avatar update --file ./portrait.png --yes
|
|
344
344
|
|
|
345
345
|
# Friends
|
|
346
|
-
amiko friends
|
|
347
|
-
amiko friends
|
|
348
|
-
amiko friends
|
|
349
|
-
amiko friends
|
|
346
|
+
amiko friends list # list
|
|
347
|
+
amiko friends add --id <userId>
|
|
348
|
+
amiko friends accept <friendshipId>
|
|
349
|
+
amiko friends remove <friendshipId> --yes
|
|
350
350
|
|
|
351
351
|
# Feed & posts
|
|
352
352
|
amiko feed # friends feed (default)
|
|
353
353
|
amiko feed --type for_you --limit 20
|
|
354
|
-
amiko post
|
|
355
|
-
amiko post
|
|
356
|
-
amiko post
|
|
357
|
-
amiko post
|
|
358
|
-
amiko post
|
|
354
|
+
amiko post create --content "hello from the CLI" # public post
|
|
355
|
+
amiko post create --content "private note" --visibility private
|
|
356
|
+
amiko post create --content "look" --media https://...jpg
|
|
357
|
+
amiko post comment --id <postId> --comment "great post"
|
|
358
|
+
amiko post comment --id <postId> --comment "nice!" --media https://...jpg
|
|
359
359
|
|
|
360
360
|
# Composio
|
|
361
|
-
amiko composio
|
|
362
|
-
amiko composio
|
|
361
|
+
amiko composio connect --app gmail # prints OAuth URL
|
|
362
|
+
amiko composio disconnect --app gmail --yes
|
|
363
363
|
```
|
|
364
364
|
|
|
365
365
|
Every new command accepts `--json` for structured output and `--twin <id>` where a target twin is needed.
|
|
366
366
|
|
|
367
|
-
**Destructive or identity-changing commands** (`docs
|
|
367
|
+
**Destructive or identity-changing commands** (`docs delete`, `friends remove`, `composio disconnect`, `voice reset`, `avatar update`, `twin update --public`) prompt for confirmation in a TTY and require `--yes` in non-interactive shells.
|
|
368
368
|
|
|
369
369
|
## API Endpoints
|
|
370
370
|
|
|
@@ -382,6 +382,10 @@ npm publish
|
|
|
382
382
|
|
|
383
383
|
## Changelog
|
|
384
384
|
|
|
385
|
+
### 0.9.0-beta.7
|
|
386
|
+
|
|
387
|
+
- **Breaking**: colon-style commands are now subcommand groups. `twin:update` → `twin update`, `docs:upload` → `docs upload`, `voice:design` → `voice design`, `avatar:update` → `avatar update`, `friends:add` → `friends add`, `post:create` → `post create`, `composio:connect` → `composio connect`, etc. No aliases — scripts and skills that used the old names must be updated. Bare `docs` and `friends` now require `list` (e.g. `amiko docs list`).
|
|
388
|
+
|
|
385
389
|
### 0.9.0-beta.0
|
|
386
390
|
|
|
387
391
|
- **Breaking**: auth simplified to `.amiko.json` + `amikoTwinToken` only. Removed `apiKey`, `privyToken`, `platformKey`, `connectedKeyId`, `agentWallets`, and `~/.amiko/config.json`.
|
package/dist/index.js
CHANGED
|
@@ -19570,6 +19570,71 @@ function detectPackageManager() {
|
|
|
19570
19570
|
return "npm";
|
|
19571
19571
|
}
|
|
19572
19572
|
}
|
|
19573
|
+
function isPrerelease(v) {
|
|
19574
|
+
return v.includes("-");
|
|
19575
|
+
}
|
|
19576
|
+
function compareSemver(a, b) {
|
|
19577
|
+
const [aMain, aPre] = a.split("-", 2);
|
|
19578
|
+
const [bMain, bPre] = b.split("-", 2);
|
|
19579
|
+
const an = aMain.split(".").map(Number);
|
|
19580
|
+
const bn = bMain.split(".").map(Number);
|
|
19581
|
+
for (let i = 0;i < 3; i++) {
|
|
19582
|
+
if ((an[i] ?? 0) !== (bn[i] ?? 0))
|
|
19583
|
+
return (an[i] ?? 0) > (bn[i] ?? 0) ? 1 : -1;
|
|
19584
|
+
}
|
|
19585
|
+
if (!aPre && !bPre)
|
|
19586
|
+
return 0;
|
|
19587
|
+
if (!aPre)
|
|
19588
|
+
return 1;
|
|
19589
|
+
if (!bPre)
|
|
19590
|
+
return -1;
|
|
19591
|
+
const ap = aPre.split(".");
|
|
19592
|
+
const bp = bPre.split(".");
|
|
19593
|
+
for (let i = 0;i < Math.max(ap.length, bp.length); i++) {
|
|
19594
|
+
const x = ap[i];
|
|
19595
|
+
const y = bp[i];
|
|
19596
|
+
if (x === undefined)
|
|
19597
|
+
return -1;
|
|
19598
|
+
if (y === undefined)
|
|
19599
|
+
return 1;
|
|
19600
|
+
const xn = /^\d+$/.test(x) ? Number(x) : NaN;
|
|
19601
|
+
const yn = /^\d+$/.test(y) ? Number(y) : NaN;
|
|
19602
|
+
if (!isNaN(xn) && !isNaN(yn)) {
|
|
19603
|
+
if (xn !== yn)
|
|
19604
|
+
return xn > yn ? 1 : -1;
|
|
19605
|
+
} else if (!isNaN(xn)) {
|
|
19606
|
+
return -1;
|
|
19607
|
+
} else if (!isNaN(yn)) {
|
|
19608
|
+
return 1;
|
|
19609
|
+
} else if (x !== y) {
|
|
19610
|
+
return x > y ? 1 : -1;
|
|
19611
|
+
}
|
|
19612
|
+
}
|
|
19613
|
+
return 0;
|
|
19614
|
+
}
|
|
19615
|
+
async function fetchDistTags(pkg) {
|
|
19616
|
+
const url2 = `https://registry.npmjs.org/-/package/${encodeURIComponent(pkg)}/dist-tags`;
|
|
19617
|
+
const res = await fetch(url2);
|
|
19618
|
+
if (!res.ok)
|
|
19619
|
+
throw new Error(`registry responded ${res.status}`);
|
|
19620
|
+
return await res.json();
|
|
19621
|
+
}
|
|
19622
|
+
async function resolveTargetVersion(pkg, currentVersion) {
|
|
19623
|
+
if (!isPrerelease(currentVersion)) {
|
|
19624
|
+
return { version: "latest", channel: "latest" };
|
|
19625
|
+
}
|
|
19626
|
+
const tags = await fetchDistTags(pkg);
|
|
19627
|
+
const latest = tags.latest;
|
|
19628
|
+
const beta = tags.beta;
|
|
19629
|
+
if (latest && beta) {
|
|
19630
|
+
return compareSemver(latest, beta) >= 0 ? { version: latest, channel: "latest" } : { version: beta, channel: "beta" };
|
|
19631
|
+
}
|
|
19632
|
+
if (beta)
|
|
19633
|
+
return { version: beta, channel: "beta" };
|
|
19634
|
+
if (latest)
|
|
19635
|
+
return { version: latest, channel: "latest" };
|
|
19636
|
+
return { version: "latest", channel: "latest" };
|
|
19637
|
+
}
|
|
19573
19638
|
var DATA_CLI = "/data/.amiko-cli";
|
|
19574
19639
|
var NPM_GLOBAL_CANDIDATES = [
|
|
19575
19640
|
"/usr/local/lib/node_modules/@heyamiko/amiko-cli",
|
|
@@ -19615,17 +19680,21 @@ function registerUpdateCommand(program2) {
|
|
|
19615
19680
|
console.log(heading("Update"));
|
|
19616
19681
|
console.log(label("Current", `v${currentVersion}`));
|
|
19617
19682
|
console.log(label("Package manager", pm));
|
|
19683
|
+
let target;
|
|
19684
|
+
try {
|
|
19685
|
+
target = await resolveTargetVersion(pkg, currentVersion);
|
|
19686
|
+
} catch {
|
|
19687
|
+
target = { version: "latest", channel: "latest" };
|
|
19688
|
+
}
|
|
19689
|
+
const installSpec = `${pkg}@${target.version}`;
|
|
19690
|
+
console.log(label("Target", target.version === "latest" ? "latest" : `${target.version} (${target.channel})`));
|
|
19618
19691
|
console.log("");
|
|
19619
|
-
const spinner = ora(
|
|
19692
|
+
const spinner = ora(`Installing ${installSpec}...`).start();
|
|
19620
19693
|
try {
|
|
19621
19694
|
if (pm === "bun") {
|
|
19622
|
-
execFileSync2("bun", ["install", "-g",
|
|
19623
|
-
stdio: "pipe"
|
|
19624
|
-
});
|
|
19695
|
+
execFileSync2("bun", ["install", "-g", installSpec], { stdio: "pipe" });
|
|
19625
19696
|
} else {
|
|
19626
|
-
execFileSync2("npm", ["install", "-g",
|
|
19627
|
-
stdio: "pipe"
|
|
19628
|
-
});
|
|
19697
|
+
execFileSync2("npm", ["install", "-g", installSpec], { stdio: "pipe" });
|
|
19629
19698
|
}
|
|
19630
19699
|
spinner.stop();
|
|
19631
19700
|
let syncedTwin = false;
|
|
@@ -19655,7 +19724,7 @@ function registerUpdateCommand(program2) {
|
|
|
19655
19724
|
console.error(error("Auto-update failed."));
|
|
19656
19725
|
console.log("");
|
|
19657
19726
|
console.log(dim("Try manually:"));
|
|
19658
|
-
console.log(dim(` ${pm} install -g ${
|
|
19727
|
+
console.log(dim(` ${pm} install -g ${installSpec}`));
|
|
19659
19728
|
process.exit(1);
|
|
19660
19729
|
}
|
|
19661
19730
|
});
|
|
@@ -20379,7 +20448,7 @@ function parseBool(raw, flag) {
|
|
|
20379
20448
|
throw new Error(`${flag} must be true or false, got "${raw}"`);
|
|
20380
20449
|
}
|
|
20381
20450
|
function registerTwinCommand(program2) {
|
|
20382
|
-
program2.command("
|
|
20451
|
+
program2.command("update").description("Update twin name, description, or public visibility").option("--name <name>", "Display name").option("--description <text>", "Description").option("--public <bool>", "Public visibility (true/false)").option("--twin <idOrName>", "Target twin id or name").option("--yes", "Skip confirmation when changing visibility").option("--json", "Output as JSON").action(async (opts) => {
|
|
20383
20452
|
if (opts.name === undefined && opts.description === undefined && opts.public === undefined) {
|
|
20384
20453
|
console.error(error("Pass at least one of --name, --description, --public"));
|
|
20385
20454
|
process.exit(1);
|
|
@@ -20414,7 +20483,7 @@ function registerTwinCommand(program2) {
|
|
|
20414
20483
|
action: `Set twin visibility to ${next ? "PUBLIC" : "PRIVATE"}`,
|
|
20415
20484
|
detail: next ? "Anyone on amiko.com will be able to find and chat with this twin." : "The twin will no longer be discoverable.",
|
|
20416
20485
|
yes: opts.yes,
|
|
20417
|
-
commandExample: `amiko twin
|
|
20486
|
+
commandExample: `amiko twin update --public ${next}`
|
|
20418
20487
|
});
|
|
20419
20488
|
}
|
|
20420
20489
|
const spinner = opts.json ? null : ora("Updating twin...").start();
|
|
@@ -20562,7 +20631,7 @@ function fmtBytes(n) {
|
|
|
20562
20631
|
return `${v.toFixed(v >= 10 ? 0 : 1)} ${units[i]}`;
|
|
20563
20632
|
}
|
|
20564
20633
|
function registerDocsCommand(program2) {
|
|
20565
|
-
program2.command("
|
|
20634
|
+
program2.command("list").description("List uploaded documents for a twin").option("--twin <idOrName>", "Target twin id or name").option("--limit <n>", "Max results", "50").option("--json", "Output as JSON").action(async (opts) => {
|
|
20566
20635
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20567
20636
|
const spinner = opts.json ? null : ora("Loading documents...").start();
|
|
20568
20637
|
try {
|
|
@@ -20598,7 +20667,7 @@ function registerDocsCommand(program2) {
|
|
|
20598
20667
|
process.exit(1);
|
|
20599
20668
|
}
|
|
20600
20669
|
});
|
|
20601
|
-
program2.command("
|
|
20670
|
+
program2.command("upload <source>").description("Upload a document (path | https URL | - for stdin)").option("--twin <idOrName>", "Target twin id or name").option("--name <filename>", "Override filename").option("--title <title>", "Document title (defaults to filename)").option("--description <text>", "Document description").option("--doc-type <type>", "Document type (e.g. 'other', 'memory')", "other").option("--stdin", "Read from stdin (source must be -)").option("--json", "Output as JSON").action(async (source, opts) => {
|
|
20602
20671
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20603
20672
|
const spinner = opts.json ? null : ora("Reading input...").start();
|
|
20604
20673
|
try {
|
|
@@ -20649,13 +20718,13 @@ function registerDocsCommand(program2) {
|
|
|
20649
20718
|
process.exit(1);
|
|
20650
20719
|
}
|
|
20651
20720
|
});
|
|
20652
|
-
program2.command("
|
|
20721
|
+
program2.command("delete <docId>").description("Delete a document").option("--twin <idOrName>", "Target twin id or name").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (docId, opts) => {
|
|
20653
20722
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20654
20723
|
await confirmDestructive({
|
|
20655
20724
|
action: `Delete document ${docId}`,
|
|
20656
20725
|
detail: "This will remove the document and its embeddings from the twin's RAG.",
|
|
20657
20726
|
yes: opts.yes,
|
|
20658
|
-
commandExample: `amiko docs
|
|
20727
|
+
commandExample: `amiko docs delete ${docId}`
|
|
20659
20728
|
});
|
|
20660
20729
|
const spinner = opts.json ? null : ora("Deleting document...").start();
|
|
20661
20730
|
try {
|
|
@@ -20668,7 +20737,7 @@ function registerDocsCommand(program2) {
|
|
|
20668
20737
|
process.exit(1);
|
|
20669
20738
|
}
|
|
20670
20739
|
});
|
|
20671
|
-
program2.command("
|
|
20740
|
+
program2.command("presign <source>").description("Get a presigned upload URL for a document (no upload)").option("--twin <idOrName>", "Target twin id or name").option("--name <filename>", "Override filename used in the request").option("--json", "Output as JSON").action(async (source, opts) => {
|
|
20672
20741
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20673
20742
|
const filename = opts.name ?? (source === "-" ? "stdin" : source.split("/").pop() ?? source);
|
|
20674
20743
|
try {
|
|
@@ -20696,7 +20765,7 @@ function twinFromFlag2(opts) {
|
|
|
20696
20765
|
}
|
|
20697
20766
|
}
|
|
20698
20767
|
function registerVoiceCommand(program2) {
|
|
20699
|
-
program2.command("
|
|
20768
|
+
program2.command("design").description("Design a voice from a text description").requiredOption("--description <text>", "Voice description (min 20 chars)").option("--twin <idOrName>", "Target twin id or name").option("--json", "Output as JSON").action(async (opts) => {
|
|
20700
20769
|
if (opts.description.trim().length < 20) {
|
|
20701
20770
|
console.error(error("--description must be at least 20 characters"));
|
|
20702
20771
|
process.exit(1);
|
|
@@ -20716,7 +20785,7 @@ function registerVoiceCommand(program2) {
|
|
|
20716
20785
|
console.log(label(`#${i + 1} id`, p.generated_voice_id ?? "?"));
|
|
20717
20786
|
}
|
|
20718
20787
|
console.log("");
|
|
20719
|
-
console.log(dim("Pick one with: amiko voice
|
|
20788
|
+
console.log(dim("Pick one with: amiko voice create --sample <id>"));
|
|
20720
20789
|
}, { json: opts.json });
|
|
20721
20790
|
} catch (e) {
|
|
20722
20791
|
spinner?.stop();
|
|
@@ -20724,7 +20793,7 @@ function registerVoiceCommand(program2) {
|
|
|
20724
20793
|
process.exit(1);
|
|
20725
20794
|
}
|
|
20726
20795
|
});
|
|
20727
|
-
program2.command("
|
|
20796
|
+
program2.command("create").description("Create a voice from a previously designed preview").requiredOption("--sample <id>", "generated_voice_id from voice design").option("--description <text>", "Optional voice description").option("--twin <idOrName>", "Target twin id or name").option("--json", "Output as JSON").action(async (opts) => {
|
|
20728
20797
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20729
20798
|
const spinner = opts.json ? null : ora("Creating voice...").start();
|
|
20730
20799
|
try {
|
|
@@ -20750,7 +20819,7 @@ function registerVoiceCommand(program2) {
|
|
|
20750
20819
|
process.exit(1);
|
|
20751
20820
|
}
|
|
20752
20821
|
});
|
|
20753
|
-
program2.command("
|
|
20822
|
+
program2.command("clone <source>").description("Clone a voice from an audio file (path | https URL | -)").option("--twin <idOrName>", "Target twin id or name").option("--name <filename>", "Override filename").option("--stdin", "Read from stdin (source must be -)").option("--json", "Output as JSON").action(async (source, opts) => {
|
|
20754
20823
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20755
20824
|
const spinner = opts.json ? null : ora("Reading audio...").start();
|
|
20756
20825
|
try {
|
|
@@ -20778,13 +20847,13 @@ function registerVoiceCommand(program2) {
|
|
|
20778
20847
|
process.exit(1);
|
|
20779
20848
|
}
|
|
20780
20849
|
});
|
|
20781
|
-
program2.command("
|
|
20850
|
+
program2.command("reset").description("Reset the twin's voice to default").option("--twin <idOrName>", "Target twin id or name").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (opts) => {
|
|
20782
20851
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20783
20852
|
await confirmDestructive({
|
|
20784
20853
|
action: "Reset voice",
|
|
20785
20854
|
detail: "This removes the custom voice. You can redesign or clone a new one later.",
|
|
20786
20855
|
yes: opts.yes,
|
|
20787
|
-
commandExample: "amiko voice
|
|
20856
|
+
commandExample: "amiko voice reset"
|
|
20788
20857
|
});
|
|
20789
20858
|
const spinner = opts.json ? null : ora("Resetting voice...").start();
|
|
20790
20859
|
try {
|
|
@@ -20801,7 +20870,7 @@ function registerVoiceCommand(program2) {
|
|
|
20801
20870
|
|
|
20802
20871
|
// src/commands/avatar.ts
|
|
20803
20872
|
function registerAvatarCommand(program2) {
|
|
20804
|
-
program2.command("
|
|
20873
|
+
program2.command("update").description("Update twin avatar image (path | https URL | - for stdin)").requiredOption("--file <source>", "Image source").option("--twin <idOrName>", "Target twin id or name").option("--stdin", "Read from stdin (file must be -)").option("--name <filename>", "Override filename").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (opts) => {
|
|
20805
20874
|
const config2 = loadConfig();
|
|
20806
20875
|
const auth = resolveAuth();
|
|
20807
20876
|
let twinId;
|
|
@@ -20818,7 +20887,7 @@ function registerAvatarCommand(program2) {
|
|
|
20818
20887
|
action: "Replace twin avatar",
|
|
20819
20888
|
detail: "The twin's public avatar will change immediately.",
|
|
20820
20889
|
yes: opts.yes,
|
|
20821
|
-
commandExample: `amiko avatar
|
|
20890
|
+
commandExample: `amiko avatar update --file ${opts.file}`
|
|
20822
20891
|
});
|
|
20823
20892
|
const spinner = opts.json ? null : ora("Reading image...").start();
|
|
20824
20893
|
try {
|
|
@@ -20860,7 +20929,7 @@ function registerAvatarCommand(program2) {
|
|
|
20860
20929
|
|
|
20861
20930
|
// src/commands/friends.ts
|
|
20862
20931
|
function registerFriendsCommand(program2) {
|
|
20863
|
-
program2.command("
|
|
20932
|
+
program2.command("list").description("List friends").option("--type <user|twin>", "Filter by friend type").option("--json", "Output as JSON").action(async (opts) => {
|
|
20864
20933
|
const auth = resolveAuth();
|
|
20865
20934
|
const spinner = opts.json ? null : ora("Loading friends...").start();
|
|
20866
20935
|
try {
|
|
@@ -20891,7 +20960,7 @@ function registerFriendsCommand(program2) {
|
|
|
20891
20960
|
process.exit(1);
|
|
20892
20961
|
}
|
|
20893
20962
|
});
|
|
20894
|
-
program2.command("
|
|
20963
|
+
program2.command("add").description("Send a friend request to a user by id").requiredOption("--id <userId>", "Target user id").option("--json", "Output as JSON").action(async (opts) => {
|
|
20895
20964
|
const auth = resolveAuth();
|
|
20896
20965
|
const spinner = opts.json ? null : ora("Sending friend request...").start();
|
|
20897
20966
|
try {
|
|
@@ -20911,7 +20980,7 @@ function registerFriendsCommand(program2) {
|
|
|
20911
20980
|
process.exit(1);
|
|
20912
20981
|
}
|
|
20913
20982
|
});
|
|
20914
|
-
program2.command("
|
|
20983
|
+
program2.command("accept <friendshipId>").description("Accept a pending friend request").option("--json", "Output as JSON").action(async (friendshipId, opts) => {
|
|
20915
20984
|
const auth = resolveAuth();
|
|
20916
20985
|
const spinner = opts.json ? null : ora("Accepting...").start();
|
|
20917
20986
|
try {
|
|
@@ -20924,11 +20993,11 @@ function registerFriendsCommand(program2) {
|
|
|
20924
20993
|
process.exit(1);
|
|
20925
20994
|
}
|
|
20926
20995
|
});
|
|
20927
|
-
program2.command("
|
|
20996
|
+
program2.command("remove <friendshipId>").description("Remove a friend").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (friendshipId, opts) => {
|
|
20928
20997
|
await confirmDestructive({
|
|
20929
20998
|
action: `Remove friend ${friendshipId}`,
|
|
20930
20999
|
yes: opts.yes,
|
|
20931
|
-
commandExample: `amiko friends
|
|
21000
|
+
commandExample: `amiko friends remove ${friendshipId}`
|
|
20932
21001
|
});
|
|
20933
21002
|
const auth = resolveAuth();
|
|
20934
21003
|
const spinner = opts.json ? null : ora("Removing...").start();
|
|
@@ -20987,7 +21056,9 @@ function registerFeedCommand(program2) {
|
|
|
20987
21056
|
process.exit(1);
|
|
20988
21057
|
}
|
|
20989
21058
|
});
|
|
20990
|
-
|
|
21059
|
+
}
|
|
21060
|
+
function registerPostCommand(program2) {
|
|
21061
|
+
program2.command("create").description("Create a post on your feed").requiredOption("--content <text>", "Post body (required, non-empty)").option("--visibility <public|private>", "Post visibility", "public").option("--media <url...>", "One or more media URLs").option("--json", "Output as JSON").action(async (opts) => {
|
|
20991
21062
|
const auth = resolveAuth();
|
|
20992
21063
|
const visibility = opts.visibility === "private" ? "private" : "public";
|
|
20993
21064
|
const spinner = opts.json ? null : ora("Publishing post...").start();
|
|
@@ -21015,7 +21086,7 @@ function registerFeedCommand(program2) {
|
|
|
21015
21086
|
process.exit(1);
|
|
21016
21087
|
}
|
|
21017
21088
|
});
|
|
21018
|
-
program2.command("
|
|
21089
|
+
program2.command("comment").description("Comment on a post").requiredOption("--id <postId>", "Target post id").requiredOption("--comment <text>", "Comment body").option("--media <url...>", "One or more media URLs to attach").option("--twin <idOrName>", "Post as this twin (agent mode)").option("--json", "Output as JSON").action(async (opts) => {
|
|
21019
21090
|
const config2 = loadConfig();
|
|
21020
21091
|
const auth = resolveAuth();
|
|
21021
21092
|
let twinId;
|
|
@@ -21067,7 +21138,7 @@ function twinFromFlag3(opts) {
|
|
|
21067
21138
|
}
|
|
21068
21139
|
}
|
|
21069
21140
|
function registerComposioCommand(program2) {
|
|
21070
|
-
program2.command("
|
|
21141
|
+
program2.command("connect").description("Start Composio OAuth for an app (gmail, github, ...)").requiredOption("--app <slug>", "App name (e.g. gmail)").option("--twin <idOrName>", "Target twin id or name").option("--redirect <url>", "Override OAuth redirect URL").option("--force", "Force reconnect if already connected").option("--json", "Output as JSON").action(async (opts) => {
|
|
21071
21142
|
const { twinId, auth } = twinFromFlag3(opts);
|
|
21072
21143
|
const spinner = opts.json ? null : ora(`Connecting ${opts.app}...`).start();
|
|
21073
21144
|
try {
|
|
@@ -21103,13 +21174,13 @@ function registerComposioCommand(program2) {
|
|
|
21103
21174
|
process.exit(1);
|
|
21104
21175
|
}
|
|
21105
21176
|
});
|
|
21106
|
-
program2.command("
|
|
21177
|
+
program2.command("disconnect").description("Disconnect a Composio app for the twin").requiredOption("--app <slug>", "App name (e.g. gmail)").option("--twin <idOrName>", "Target twin id or name").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (opts) => {
|
|
21107
21178
|
const { twinId, auth } = twinFromFlag3(opts);
|
|
21108
21179
|
await confirmDestructive({
|
|
21109
21180
|
action: `Disconnect ${opts.app}`,
|
|
21110
21181
|
detail: "The twin will lose access to the app's tools until reconnected.",
|
|
21111
21182
|
yes: opts.yes,
|
|
21112
|
-
commandExample: `amiko composio
|
|
21183
|
+
commandExample: `amiko composio disconnect --app ${opts.app}`
|
|
21113
21184
|
});
|
|
21114
21185
|
const spinner = opts.json ? null : ora("Finding connection...").start();
|
|
21115
21186
|
try {
|
|
@@ -21235,6 +21306,13 @@ var program2 = new Command;
|
|
|
21235
21306
|
program2.name("amiko").description("Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call marketplace services").version(PKG_VERSION);
|
|
21236
21307
|
var market = program2.command("market").description("MPP marketplace — discover and call paid AMIKO services");
|
|
21237
21308
|
var wallets = program2.command("wallets").description("Manage twin wallets — list, swap, bridge");
|
|
21309
|
+
var twin = program2.command("twin").description("Update twin identity (name, description, visibility)");
|
|
21310
|
+
var docs = program2.command("docs").description("Manage twin RAG documents — list, upload, delete, presign");
|
|
21311
|
+
var voice = program2.command("voice").description("Manage twin voice — design, create, clone, reset");
|
|
21312
|
+
var avatar = program2.command("avatar").description("Manage twin avatar image");
|
|
21313
|
+
var friends = program2.command("friends").description("Manage friendships — list, add, accept, remove");
|
|
21314
|
+
var post = program2.command("post").description("Create posts and comments on the feed");
|
|
21315
|
+
var composio = program2.command("composio").description("Manage Composio app connections");
|
|
21238
21316
|
registerCreditsCommand(program2);
|
|
21239
21317
|
registerSearchCommand(market);
|
|
21240
21318
|
registerImageCommand(market);
|
|
@@ -21248,11 +21326,12 @@ registerServicesCommand(market);
|
|
|
21248
21326
|
registerDiscoveryCommand(market);
|
|
21249
21327
|
registerUpdateCommand(program2);
|
|
21250
21328
|
registerAccountsCommand(program2);
|
|
21251
|
-
registerTwinCommand(
|
|
21252
|
-
registerDocsCommand(
|
|
21253
|
-
registerVoiceCommand(
|
|
21254
|
-
registerAvatarCommand(
|
|
21255
|
-
registerFriendsCommand(
|
|
21329
|
+
registerTwinCommand(twin);
|
|
21330
|
+
registerDocsCommand(docs);
|
|
21331
|
+
registerVoiceCommand(voice);
|
|
21332
|
+
registerAvatarCommand(avatar);
|
|
21333
|
+
registerFriendsCommand(friends);
|
|
21256
21334
|
registerFeedCommand(program2);
|
|
21257
|
-
|
|
21335
|
+
registerPostCommand(post);
|
|
21336
|
+
registerComposioCommand(composio);
|
|
21258
21337
|
program2.parse();
|
package/package.json
CHANGED
package/skills/SKILL.md
CHANGED
|
@@ -21,11 +21,11 @@ The top level has three groups:
|
|
|
21
21
|
- `amiko wallets <cmd>` — wallet operations (list, balance, swap, bridge)
|
|
22
22
|
- `amiko credits <cmd>` — credit balance and topup
|
|
23
23
|
|
|
24
|
-
Plus
|
|
24
|
+
Plus subcommand groups: `twin <action>`, `docs <action>`, `voice <action>`, `avatar <action>`, `friends <action>`, `post <action>`, `composio <action>`. Plus flat commands: `config`, `update`, `accounts`, `info`, `feed`.
|
|
25
25
|
|
|
26
26
|
## Critical Rules
|
|
27
27
|
|
|
28
|
-
1. **Every paid / value-moving command is hard-gated on `--yes` in a non-interactive shell.** The CLI *refuses* to run `market image`, `market search`, `market amazon search`, `market service call`, `market service tts`, `market service stt`, `market service chat`, `credits topup`, `wallets swap send`, or `wallets bridge send` unless `--yes` is passed. The refusal is loud: it prints the cost and the command you should re-run. **Quote the cost to the user, get explicit approval, THEN append `--yes`**. Same for destructive non-paid commands (`twin
|
|
28
|
+
1. **Every paid / value-moving command is hard-gated on `--yes` in a non-interactive shell.** The CLI *refuses* to run `market image`, `market search`, `market amazon search`, `market service call`, `market service tts`, `market service stt`, `market service chat`, `credits topup`, `wallets swap send`, or `wallets bridge send` unless `--yes` is passed. The refusal is loud: it prints the cost and the command you should re-run. **Quote the cost to the user, get explicit approval, THEN append `--yes`**. Same for destructive non-paid commands (`twin update --public`, `docs delete`, `friends remove`, `avatar update`, `voice reset`, `composio disconnect`).
|
|
29
29
|
2. **After every paid command, report the remaining balance.** The CLI prints a `Balance: N credits` line at the end of every paid command — include that figure in your reply.
|
|
30
30
|
3. **Never retry a failed command.** Report the error and stop. Every paid call costs tokens even on failure.
|
|
31
31
|
4. **Never suggest `amiko login` or `amiko connect`.** These don't exist. Auth is automatic via `.amiko.json`.
|
|
@@ -119,9 +119,9 @@ Paid market commands require `--wallet <address>` (the Solana wallet that pays)
|
|
|
119
119
|
```bash
|
|
120
120
|
amiko accounts # resolved identity (authenticated, userId, twinId, platform)
|
|
121
121
|
amiko info # twin info (name, description, public, voice, avatar)
|
|
122
|
-
amiko twin
|
|
123
|
-
amiko twin
|
|
124
|
-
amiko twin
|
|
122
|
+
amiko twin update --name "New Name"
|
|
123
|
+
amiko twin update --description "..."
|
|
124
|
+
amiko twin update --public true --yes # destructive — requires --yes in non-TTY
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
All twin-scoped commands accept `--twin <id>` to target a non-default twin.
|
|
@@ -129,37 +129,37 @@ All twin-scoped commands accept `--twin <id>` to target a non-default twin.
|
|
|
129
129
|
## Documents (RAG)
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
amiko docs
|
|
133
|
-
amiko docs
|
|
134
|
-
amiko docs
|
|
135
|
-
cat file.pdf | amiko docs
|
|
136
|
-
amiko docs
|
|
137
|
-
amiko docs
|
|
132
|
+
amiko docs list # list
|
|
133
|
+
amiko docs upload ./notes.pdf # path
|
|
134
|
+
amiko docs upload https://example.com/x.pdf # URL
|
|
135
|
+
cat file.pdf | amiko docs upload - --stdin --name file.pdf
|
|
136
|
+
amiko docs delete <docId> --yes # destructive
|
|
137
|
+
amiko docs presign ./file.pdf # presigned S3 URL only
|
|
138
138
|
```
|
|
139
139
|
|
|
140
140
|
## Voice
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
|
-
amiko voice
|
|
144
|
-
amiko voice
|
|
145
|
-
amiko voice
|
|
146
|
-
amiko voice
|
|
143
|
+
amiko voice design --description "warm, low, male, confident, measured" # min 20 chars
|
|
144
|
+
amiko voice create --sample <generated_voice_id>
|
|
145
|
+
amiko voice clone ./me.mp3 # path | URL | -
|
|
146
|
+
amiko voice reset --yes # destructive
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
## Avatar
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
amiko avatar
|
|
152
|
+
amiko avatar update --file ./portrait.png --yes # max 5 MB, destructive
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
## Friends
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
|
-
amiko friends
|
|
159
|
-
amiko friends --type user
|
|
160
|
-
amiko friends
|
|
161
|
-
amiko friends
|
|
162
|
-
amiko friends
|
|
158
|
+
amiko friends list # list all
|
|
159
|
+
amiko friends list --type user # filter
|
|
160
|
+
amiko friends add --id <userId>
|
|
161
|
+
amiko friends accept <friendshipId>
|
|
162
|
+
amiko friends remove <friendshipId> --yes # destructive
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
## Feed & Posts
|
|
@@ -168,19 +168,19 @@ amiko friends:remove <friendshipId> --yes # destructive
|
|
|
168
168
|
amiko feed # friends feed (default)
|
|
169
169
|
amiko feed --type for_you --limit 20
|
|
170
170
|
amiko feed --hashtag ai
|
|
171
|
-
amiko post
|
|
172
|
-
amiko post
|
|
173
|
-
amiko post
|
|
174
|
-
amiko post
|
|
175
|
-
amiko post
|
|
176
|
-
amiko post
|
|
171
|
+
amiko post create --content "hello from the CLI"
|
|
172
|
+
amiko post create --content "private note" --visibility private
|
|
173
|
+
amiko post create --content "look" --media https://...jpg
|
|
174
|
+
amiko post comment --id <postId> --comment "great post"
|
|
175
|
+
amiko post comment --id <postId> --comment "look" --media https://...jpg
|
|
176
|
+
amiko post comment --id <postId> --comment "..." --twin <id>
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
## Composio
|
|
180
180
|
|
|
181
181
|
```bash
|
|
182
|
-
amiko composio
|
|
183
|
-
amiko composio
|
|
182
|
+
amiko composio connect --app gmail # prints OAuth URL
|
|
183
|
+
amiko composio disconnect --app gmail --yes # destructive
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
## Other
|