@heyamiko/amiko-cli 0.8.0 → 0.8.1
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 +7 -6
- package/dist/index.js +85 -85
- package/package.json +1 -1
- package/skills/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @heyamiko/amiko-cli (v0.8.
|
|
1
|
+
# @heyamiko/amiko-cli (v0.8.1)
|
|
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
|
|
|
@@ -148,19 +148,20 @@ amiko swap send 0.5 USDC AMIKO --yes
|
|
|
148
148
|
amiko swap send 100 AMIKO SOL --slippage 100
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
Swaps execute via Jupiter on Solana. Supports SOL, USDC, USDT, AMIKO, PYUSD, BONK, JUP, RAY, JitoSOL, mSOL, or any mint address.
|
|
151
|
+
Swaps execute via Jupiter on Solana. Supports SOL, USDC, USDT, AMIKO, PYUSD, BONK, JUP, RAY, JitoSOL, mSOL, or any mint address. `swap send` is hard-gated: in a non-interactive shell you must pass `--yes` after quoting the cost to the user (`Solana gas + 10bps platform fee`).
|
|
152
152
|
|
|
153
153
|
## Bridge
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
156
|
amiko bridge quote <amount> # cross-chain USDC quote via Across Protocol
|
|
157
|
-
amiko bridge send <amount> # execute bridge transfer
|
|
157
|
+
amiko bridge send <amount> # execute bridge transfer (gated — requires --yes in non-TTY)
|
|
158
|
+
amiko bridge send <amount> --raw # print transaction JSON without sending (no gate)
|
|
158
159
|
amiko bridge status <txHash> # check bridge status
|
|
159
160
|
amiko bridge routes # available bridge routes
|
|
160
161
|
amiko bridge limits # min/max limits per route
|
|
161
162
|
```
|
|
162
163
|
|
|
163
|
-
Default route: Solana → Tempo. Use `--from` and `--to` flags for other chains.
|
|
164
|
+
Default route: Solana → Tempo. Use `--from` and `--to` flags for other chains. Like `swap send`, `bridge send` refuses to run in a non-interactive shell without `--yes` so agents must quote the Across fee + gas to the user before executing.
|
|
164
165
|
|
|
165
166
|
## MPP Services
|
|
166
167
|
|
|
@@ -191,7 +192,7 @@ Audio and image endpoints upload to Supabase Storage and return permanent URLs.
|
|
|
191
192
|
|
|
192
193
|
## Confirmation Gate for Paid Commands
|
|
193
194
|
|
|
194
|
-
Every paid command (`image`, `search`, `amazon search`, `service tts`, `service stt`, `service chat`, `service call`, `credits topup`) requires explicit approval before spending:
|
|
195
|
+
Every paid / value-moving command (`image`, `search`, `amazon search`, `service tts`, `service stt`, `service chat`, `service call`, `credits topup`, `swap send`, `bridge send`) requires explicit approval before spending:
|
|
195
196
|
|
|
196
197
|
- **Human, interactive shell** — the command prints the cost and prompts `Proceed? [y/N]`. Answer `y` to run.
|
|
197
198
|
- **Agent / non-interactive shell** — the command *refuses* to run without `--yes`, with a message telling the agent what to do:
|
|
@@ -206,7 +207,7 @@ Every paid command (`image`, `search`, `amazon search`, `service tts`, `service
|
|
|
206
207
|
amiko image "a sunset over mountains" --yes
|
|
207
208
|
```
|
|
208
209
|
|
|
209
|
-
This makes cost confirmation effectively mandatory regardless of which model drives the agent — weak models can no longer silently burn tokens by ignoring the skill docs.
|
|
210
|
+
This makes cost confirmation effectively mandatory regardless of which model drives the agent — weak models can no longer silently burn tokens by ignoring the skill docs. The same refusal fires for `swap send` (Solana gas + 10 bps platform fee) and `bridge send` (Across fee + gas), so an agent cannot move tokens without a round-trip through user approval.
|
|
210
211
|
|
|
211
212
|
## Error Output
|
|
212
213
|
|
package/dist/index.js
CHANGED
|
@@ -73750,6 +73750,69 @@ Run "amiko login" again to re-authenticate, or "amiko logout" to sign out.
|
|
|
73750
73750
|
});
|
|
73751
73751
|
}
|
|
73752
73752
|
|
|
73753
|
+
// src/lib/confirm.ts
|
|
73754
|
+
import readline from "node:readline";
|
|
73755
|
+
function promptYesNo(question) {
|
|
73756
|
+
const rl = readline.createInterface({
|
|
73757
|
+
input: process.stdin,
|
|
73758
|
+
output: process.stdout
|
|
73759
|
+
});
|
|
73760
|
+
return new Promise((resolve2) => {
|
|
73761
|
+
rl.question(question, (answer) => {
|
|
73762
|
+
rl.close();
|
|
73763
|
+
resolve2(/^y(es)?$/i.test(answer.trim()));
|
|
73764
|
+
});
|
|
73765
|
+
});
|
|
73766
|
+
}
|
|
73767
|
+
async function confirmDestructive(args) {
|
|
73768
|
+
if (args.yes)
|
|
73769
|
+
return;
|
|
73770
|
+
if (process.stdin.isTTY) {
|
|
73771
|
+
console.log("");
|
|
73772
|
+
console.log(warn(args.action));
|
|
73773
|
+
if (args.detail)
|
|
73774
|
+
console.log(dim(args.detail));
|
|
73775
|
+
const ok = await promptYesNo("Proceed? [y/N] ");
|
|
73776
|
+
if (!ok) {
|
|
73777
|
+
console.log(dim("Cancelled."));
|
|
73778
|
+
process.exit(0);
|
|
73779
|
+
}
|
|
73780
|
+
return;
|
|
73781
|
+
}
|
|
73782
|
+
console.error(error(`Refusing to run without --yes (non-interactive shell).`));
|
|
73783
|
+
console.error("");
|
|
73784
|
+
console.error(`Action: ${args.action}`);
|
|
73785
|
+
if (args.detail)
|
|
73786
|
+
console.error(dim(args.detail));
|
|
73787
|
+
console.error("");
|
|
73788
|
+
console.error(dim("Re-run with --yes to confirm:"));
|
|
73789
|
+
console.error(dim(` ${args.commandExample} --yes`));
|
|
73790
|
+
process.exit(2);
|
|
73791
|
+
}
|
|
73792
|
+
async function requireApproval(args) {
|
|
73793
|
+
if (args.yes)
|
|
73794
|
+
return;
|
|
73795
|
+
if (process.stdin.isTTY) {
|
|
73796
|
+
console.log("");
|
|
73797
|
+
console.log(`About to run: ${args.summary}`);
|
|
73798
|
+
console.log(`Cost: ${args.cost}`);
|
|
73799
|
+
const ok = await promptYesNo("Proceed? [y/N] ");
|
|
73800
|
+
if (!ok) {
|
|
73801
|
+
console.log(dim("Cancelled."));
|
|
73802
|
+
process.exit(0);
|
|
73803
|
+
}
|
|
73804
|
+
return;
|
|
73805
|
+
}
|
|
73806
|
+
console.error(error(`Refusing to run without --yes (non-interactive shell detected).`));
|
|
73807
|
+
console.error("");
|
|
73808
|
+
console.error(`This command will cost ${args.cost}.`);
|
|
73809
|
+
console.error(`Action: ${args.summary}`);
|
|
73810
|
+
console.error("");
|
|
73811
|
+
console.error(dim(`Quote the cost to the user, get their explicit approval, then re-run with --yes:`));
|
|
73812
|
+
console.error(dim(` ${args.commandExample} --yes`));
|
|
73813
|
+
process.exit(2);
|
|
73814
|
+
}
|
|
73815
|
+
|
|
73753
73816
|
// src/lib/across.ts
|
|
73754
73817
|
function getBridgeBase() {
|
|
73755
73818
|
const config = loadConfig();
|
|
@@ -73969,7 +74032,7 @@ function registerBridgeCommand(program2) {
|
|
|
73969
74032
|
process.exit(1);
|
|
73970
74033
|
}
|
|
73971
74034
|
});
|
|
73972
|
-
cmd.command("send").description("Execute a USDC bridge transfer via Across").argument("<amount>", "Amount of USDC to bridge (e.g., 10, 5.50)").option("--from <chain>", "Origin chain (default: solana)", "solana").option("--to <chain>", "Destination chain (default: tempo)", "tempo").option("--recipient <address>", "Recipient address on destination chain").option("--depositor <address>", "Depositor address on origin chain").option("--raw", "Output raw transaction JSON for manual signing").action(async (amountStr, opts) => {
|
|
74035
|
+
cmd.command("send").description("Execute a USDC bridge transfer via Across").argument("<amount>", "Amount of USDC to bridge (e.g., 10, 5.50)").option("--from <chain>", "Origin chain (default: solana)", "solana").option("--to <chain>", "Destination chain (default: tempo)", "tempo").option("--recipient <address>", "Recipient address on destination chain").option("--depositor <address>", "Depositor address on origin chain").option("--raw", "Output raw transaction JSON for manual signing").option("--yes", "Skip confirmation (only after the user has approved)").action(async (amountStr, opts) => {
|
|
73973
74036
|
const spinner = ora("Preparing bridge transaction...").start();
|
|
73974
74037
|
try {
|
|
73975
74038
|
const originChainId = resolveChainId(opts.from);
|
|
@@ -74009,6 +74072,14 @@ function registerBridgeCommand(program2) {
|
|
|
74009
74072
|
if (quote.fees?.total) {
|
|
74010
74073
|
console.log(label("Fee", `${formatUsdcAmount(quote.fees.total.amount)} USDC`));
|
|
74011
74074
|
}
|
|
74075
|
+
if (!opts.raw) {
|
|
74076
|
+
await requireApproval({
|
|
74077
|
+
cost: quote.fees?.total ? `${formatUsdcAmount(quote.fees.total.amount)} USDC bridge fee + gas` : "gas + Across fee",
|
|
74078
|
+
summary: `bridge ${formatUsdcAmount(quote.inputAmount)} USDC ${originName} → ${destName}`,
|
|
74079
|
+
yes: opts.yes,
|
|
74080
|
+
commandExample: `amiko bridge send ${amountStr} --from ${opts.from} --to ${opts.to}`
|
|
74081
|
+
});
|
|
74082
|
+
}
|
|
74012
74083
|
if (opts.raw) {
|
|
74013
74084
|
console.log("");
|
|
74014
74085
|
console.log(heading("Transaction Data"));
|
|
@@ -74412,7 +74483,7 @@ Tip: you can also generate a connect link from your Amiko settings`));
|
|
|
74412
74483
|
}
|
|
74413
74484
|
|
|
74414
74485
|
// src/commands/credits.ts
|
|
74415
|
-
import
|
|
74486
|
+
import readline2 from "node:readline";
|
|
74416
74487
|
|
|
74417
74488
|
// src/lib/mpp-topup.ts
|
|
74418
74489
|
async function mppCreditsTopup(params) {
|
|
@@ -74475,11 +74546,11 @@ async function mppCreditsTopup(params) {
|
|
|
74475
74546
|
}
|
|
74476
74547
|
|
|
74477
74548
|
// src/commands/credits.ts
|
|
74478
|
-
function
|
|
74549
|
+
function promptYesNo2(question) {
|
|
74479
74550
|
if (!process.stdin.isTTY) {
|
|
74480
74551
|
return Promise.resolve(false);
|
|
74481
74552
|
}
|
|
74482
|
-
const rl =
|
|
74553
|
+
const rl = readline2.createInterface({
|
|
74483
74554
|
input: process.stdin,
|
|
74484
74555
|
output: process.stdout
|
|
74485
74556
|
});
|
|
@@ -74717,7 +74788,7 @@ function registerCreditsCommand(program2) {
|
|
|
74717
74788
|
console.log(label("USD", `$${usdAmount.toFixed(2)}`));
|
|
74718
74789
|
console.log(dim("Charged via MPP connected key."));
|
|
74719
74790
|
console.log("");
|
|
74720
|
-
const ok = await
|
|
74791
|
+
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
74721
74792
|
if (!ok) {
|
|
74722
74793
|
console.log(dim("Top-up cancelled."));
|
|
74723
74794
|
process.exit(0);
|
|
@@ -74761,7 +74832,7 @@ function registerCreditsCommand(program2) {
|
|
|
74761
74832
|
console.log(dim("Tokens will be transferred from your agent wallet to the treasury."));
|
|
74762
74833
|
console.log("");
|
|
74763
74834
|
if (!options.yes) {
|
|
74764
|
-
const confirmed = await
|
|
74835
|
+
const confirmed = await promptYesNo2("Proceed? [y/N] ");
|
|
74765
74836
|
if (!confirmed) {
|
|
74766
74837
|
console.log(dim("Top-up cancelled."));
|
|
74767
74838
|
process.exit(0);
|
|
@@ -75006,20 +75077,12 @@ function registerSwapCommand(program2) {
|
|
|
75006
75077
|
console.log(label("Route", dim(route)));
|
|
75007
75078
|
console.log(label("Wallet", truncAddr(wallet)));
|
|
75008
75079
|
console.log("");
|
|
75009
|
-
|
|
75010
|
-
|
|
75011
|
-
|
|
75012
|
-
|
|
75013
|
-
|
|
75014
|
-
|
|
75015
|
-
});
|
|
75016
|
-
const answer = await new Promise((resolve2) => rl.question("Confirm swap? (y/N) ", resolve2));
|
|
75017
|
-
rl.close();
|
|
75018
|
-
if (answer.toLowerCase() !== "y") {
|
|
75019
|
-
console.log(dim("Cancelled."));
|
|
75020
|
-
process.exit(0);
|
|
75021
|
-
}
|
|
75022
|
-
}
|
|
75080
|
+
await requireApproval({
|
|
75081
|
+
cost: "Solana gas + 10bps platform fee",
|
|
75082
|
+
summary: `swap ${amountStr} ${fromToken.toUpperCase()} → ~${(Number(quote.outAmount) / 10 ** output.decimals).toFixed(6)} ${output.symbol}`,
|
|
75083
|
+
yes: opts.yes,
|
|
75084
|
+
commandExample: `amiko swap send ${amountStr} ${fromToken} ${toToken}`
|
|
75085
|
+
});
|
|
75023
75086
|
const swapSpinner = ora("Executing swap via Crossmint...").start();
|
|
75024
75087
|
const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
|
|
75025
75088
|
const billingBase = auth.billingBase || "https://billing.heyamiko.com";
|
|
@@ -75236,69 +75299,6 @@ async function reportHttpError(res, label2) {
|
|
|
75236
75299
|
console.error(String(pretty).slice(0, 2000));
|
|
75237
75300
|
}
|
|
75238
75301
|
|
|
75239
|
-
// src/lib/confirm.ts
|
|
75240
|
-
import readline2 from "node:readline";
|
|
75241
|
-
function promptYesNo2(question) {
|
|
75242
|
-
const rl = readline2.createInterface({
|
|
75243
|
-
input: process.stdin,
|
|
75244
|
-
output: process.stdout
|
|
75245
|
-
});
|
|
75246
|
-
return new Promise((resolve2) => {
|
|
75247
|
-
rl.question(question, (answer) => {
|
|
75248
|
-
rl.close();
|
|
75249
|
-
resolve2(/^y(es)?$/i.test(answer.trim()));
|
|
75250
|
-
});
|
|
75251
|
-
});
|
|
75252
|
-
}
|
|
75253
|
-
async function confirmDestructive(args) {
|
|
75254
|
-
if (args.yes)
|
|
75255
|
-
return;
|
|
75256
|
-
if (process.stdin.isTTY) {
|
|
75257
|
-
console.log("");
|
|
75258
|
-
console.log(warn(args.action));
|
|
75259
|
-
if (args.detail)
|
|
75260
|
-
console.log(dim(args.detail));
|
|
75261
|
-
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
75262
|
-
if (!ok) {
|
|
75263
|
-
console.log(dim("Cancelled."));
|
|
75264
|
-
process.exit(0);
|
|
75265
|
-
}
|
|
75266
|
-
return;
|
|
75267
|
-
}
|
|
75268
|
-
console.error(error(`Refusing to run without --yes (non-interactive shell).`));
|
|
75269
|
-
console.error("");
|
|
75270
|
-
console.error(`Action: ${args.action}`);
|
|
75271
|
-
if (args.detail)
|
|
75272
|
-
console.error(dim(args.detail));
|
|
75273
|
-
console.error("");
|
|
75274
|
-
console.error(dim("Re-run with --yes to confirm:"));
|
|
75275
|
-
console.error(dim(` ${args.commandExample} --yes`));
|
|
75276
|
-
process.exit(2);
|
|
75277
|
-
}
|
|
75278
|
-
async function requireApproval(args) {
|
|
75279
|
-
if (args.yes)
|
|
75280
|
-
return;
|
|
75281
|
-
if (process.stdin.isTTY) {
|
|
75282
|
-
console.log("");
|
|
75283
|
-
console.log(`About to run: ${args.summary}`);
|
|
75284
|
-
console.log(`Cost: ${args.cost}`);
|
|
75285
|
-
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
75286
|
-
if (!ok) {
|
|
75287
|
-
console.log(dim("Cancelled."));
|
|
75288
|
-
process.exit(0);
|
|
75289
|
-
}
|
|
75290
|
-
return;
|
|
75291
|
-
}
|
|
75292
|
-
console.error(error(`Refusing to run without --yes (non-interactive shell detected).`));
|
|
75293
|
-
console.error("");
|
|
75294
|
-
console.error(`This command will cost ${args.cost}.`);
|
|
75295
|
-
console.error(`Action: ${args.summary}`);
|
|
75296
|
-
console.error("");
|
|
75297
|
-
console.error(dim(`Quote the cost to the user, get their explicit approval, then re-run with --yes:`));
|
|
75298
|
-
console.error(dim(` ${args.commandExample} --yes`));
|
|
75299
|
-
process.exit(2);
|
|
75300
|
-
}
|
|
75301
|
-
|
|
75302
75302
|
// src/commands/search.ts
|
|
75303
75303
|
var TREASURY = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
75304
75304
|
function registerSearchCommand(program2) {
|
|
@@ -76025,10 +76025,10 @@ async function amikoWebFetch(auth, path2, opts = {}) {
|
|
|
76025
76025
|
function formatError2(status, body, path2) {
|
|
76026
76026
|
const prefix = `${status} ${path2}`;
|
|
76027
76027
|
if (status === 401) {
|
|
76028
|
-
return `${prefix}: unauthorized.
|
|
76028
|
+
return `${prefix}: unauthorized. The stored token is invalid or expired; re-link this device to Amiko.`;
|
|
76029
76029
|
}
|
|
76030
76030
|
if (status === 403) {
|
|
76031
|
-
return `${prefix}: forbidden. The
|
|
76031
|
+
return `${prefix}: forbidden. The current auth context does not have access to this resource.`;
|
|
76032
76032
|
}
|
|
76033
76033
|
if (!body)
|
|
76034
76034
|
return prefix;
|
package/package.json
CHANGED
package/skills/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ The `amiko` CLI is installed globally. Auth and payments are automatic via `.ami
|
|
|
15
15
|
|
|
16
16
|
## Critical Rules
|
|
17
17
|
|
|
18
|
-
1. **Every paid command is hard-gated on `--yes` in a non-interactive shell.** The CLI will *refuse* to run `image`, `search`, `amazon search`, `service call`, `service tts`, `service stt`, `service chat`,
|
|
18
|
+
1. **Every paid / value-moving command is hard-gated on `--yes` in a non-interactive shell.** The CLI will *refuse* to run `image`, `search`, `amazon search`, `service call`, `service tts`, `service stt`, `service chat`, `credits topup`, `swap send`, or `bridge send` unless you pass `--yes`. The refusal is loud: it prints the cost and the command you should re-run with `--yes` appended. This means: **you must first quote the cost to the user, get their explicit approval, and only then append `--yes`**. If the user didn't approve, do not add `--yes`. The same applies to destructive non-paid commands (`twin:update --public`, `docs:delete`, `friends:remove`, `avatar:update`, `voice:reset`, `composio:disconnect`).
|
|
19
19
|
2. **After every paid command, report the remaining balance to the user.** The CLI prints a `Balance: N credits (~$X.XX)` line at the end of every paid command — include that figure in your reply so the user knows what they have left.
|
|
20
20
|
3. **Never retry a failed command.** If a command returns an error, report it and stop. Every paid call costs tokens even on failure.
|
|
21
21
|
4. **Never suggest `amiko login` or `amiko connect`.** These commands don't exist. Auth is automatic via `.amiko.json`.
|