@heyamiko/amiko-cli 0.9.0-beta.0 → 0.9.0-beta.10
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 +88 -74
- package/dist/index.js +454 -203
- package/package.json +1 -1
- package/skills/SKILL.md +154 -165
package/dist/index.js
CHANGED
|
@@ -17287,7 +17287,6 @@ function resolveAuth() {
|
|
|
17287
17287
|
twinId: asString(parsed.amikoTwinId) ?? asString(parsed.AMIKO_TWIN_ID),
|
|
17288
17288
|
userId: asString(parsed.amikoUserId) ?? asString(parsed.AMIKO_USER_ID),
|
|
17289
17289
|
platformUrl: asString(parsed.amikoPlatformUrl) ?? asString(parsed.AMIKO_PLATFORM_URL),
|
|
17290
|
-
billingBase: asString(parsed.billingBase),
|
|
17291
17290
|
apiBase: asString(parsed.apiBase)
|
|
17292
17291
|
};
|
|
17293
17292
|
}
|
|
@@ -17305,7 +17304,6 @@ function requireAuth() {
|
|
|
17305
17304
|
// src/lib/config.ts
|
|
17306
17305
|
var DEFAULTS = {
|
|
17307
17306
|
apiBase: "https://mpp.amikomarkets.com",
|
|
17308
|
-
billingBase: "https://billing.heyamiko.com",
|
|
17309
17307
|
platformUrl: "https://platform.heyamiko.com",
|
|
17310
17308
|
siteBase: "https://platform.heyamiko.com"
|
|
17311
17309
|
};
|
|
@@ -17313,7 +17311,6 @@ function loadConfig() {
|
|
|
17313
17311
|
const auth = resolveAuth();
|
|
17314
17312
|
return {
|
|
17315
17313
|
apiBase: auth.apiBase ?? DEFAULTS.apiBase,
|
|
17316
|
-
billingBase: auth.billingBase ?? DEFAULTS.billingBase,
|
|
17317
17314
|
platformUrl: auth.platformUrl ?? DEFAULTS.platformUrl,
|
|
17318
17315
|
siteBase: DEFAULTS.siteBase,
|
|
17319
17316
|
twinToken: auth.twinToken,
|
|
@@ -17385,7 +17382,6 @@ function registerConfigCommand(program2) {
|
|
|
17385
17382
|
console.log("");
|
|
17386
17383
|
console.log(heading("Endpoints"));
|
|
17387
17384
|
console.log(label(" MPP service", config.apiBase));
|
|
17388
|
-
console.log(label(" Billing API", config.billingBase));
|
|
17389
17385
|
console.log(label(" Platform", config.platformUrl));
|
|
17390
17386
|
console.log("");
|
|
17391
17387
|
console.log(heading("Identity"));
|
|
@@ -18488,6 +18484,104 @@ async function requireApproval(args) {
|
|
|
18488
18484
|
process.exit(2);
|
|
18489
18485
|
}
|
|
18490
18486
|
|
|
18487
|
+
// src/lib/amiko-web.ts
|
|
18488
|
+
var DEFAULT_PLATFORM_URL = "https://platform.heyamiko.com";
|
|
18489
|
+
function baseUrl(auth) {
|
|
18490
|
+
const url = auth.platformUrl || DEFAULT_PLATFORM_URL;
|
|
18491
|
+
return url.replace(/\/$/, "");
|
|
18492
|
+
}
|
|
18493
|
+
function authHeader(auth) {
|
|
18494
|
+
if (auth.twinToken)
|
|
18495
|
+
return `Bearer ${auth.twinToken}`;
|
|
18496
|
+
throw new Error("No twin token found. Place an .amiko.json file with amikoTwinToken in the current directory or any parent.");
|
|
18497
|
+
}
|
|
18498
|
+
async function amikoWebFetch(auth, path, opts = {}) {
|
|
18499
|
+
const url = new URL(`${baseUrl(auth)}${path}`);
|
|
18500
|
+
if (opts.query) {
|
|
18501
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
18502
|
+
if (v !== undefined && v !== null)
|
|
18503
|
+
url.searchParams.set(k, String(v));
|
|
18504
|
+
}
|
|
18505
|
+
}
|
|
18506
|
+
const headers = {
|
|
18507
|
+
Authorization: authHeader(auth),
|
|
18508
|
+
...opts.headers
|
|
18509
|
+
};
|
|
18510
|
+
let body;
|
|
18511
|
+
if (opts.multipart) {
|
|
18512
|
+
body = opts.multipart;
|
|
18513
|
+
} else if (opts.rawBody) {
|
|
18514
|
+
body = opts.rawBody;
|
|
18515
|
+
if (opts.rawContentType)
|
|
18516
|
+
headers["Content-Type"] = opts.rawContentType;
|
|
18517
|
+
} else if (opts.body) {
|
|
18518
|
+
body = JSON.stringify(opts.body);
|
|
18519
|
+
headers["Content-Type"] = "application/json";
|
|
18520
|
+
}
|
|
18521
|
+
const controller = new AbortController;
|
|
18522
|
+
const timeoutMs = opts.timeoutMs ?? 30000;
|
|
18523
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
18524
|
+
let res;
|
|
18525
|
+
try {
|
|
18526
|
+
res = await fetch(url, {
|
|
18527
|
+
method: opts.method ?? "GET",
|
|
18528
|
+
headers,
|
|
18529
|
+
body,
|
|
18530
|
+
signal: controller.signal
|
|
18531
|
+
});
|
|
18532
|
+
} finally {
|
|
18533
|
+
clearTimeout(timer);
|
|
18534
|
+
}
|
|
18535
|
+
if (!res.ok) {
|
|
18536
|
+
const text = await res.text().catch(() => "");
|
|
18537
|
+
const err = new Error(formatError(res.status, text, path));
|
|
18538
|
+
err.status = res.status;
|
|
18539
|
+
err.body = text;
|
|
18540
|
+
throw err;
|
|
18541
|
+
}
|
|
18542
|
+
const ctype = res.headers.get("content-type") || "";
|
|
18543
|
+
if (ctype.includes("application/json")) {
|
|
18544
|
+
return await res.json();
|
|
18545
|
+
}
|
|
18546
|
+
return await res.text();
|
|
18547
|
+
}
|
|
18548
|
+
function formatError(status, body, path) {
|
|
18549
|
+
const prefix = `${status} ${path}`;
|
|
18550
|
+
if (status === 401) {
|
|
18551
|
+
return `${prefix}: unauthorized. The stored token is invalid or expired; re-link this device to Amiko.`;
|
|
18552
|
+
}
|
|
18553
|
+
if (status === 403) {
|
|
18554
|
+
return `${prefix}: forbidden. The current auth context does not have access to this resource.`;
|
|
18555
|
+
}
|
|
18556
|
+
if (!body)
|
|
18557
|
+
return prefix;
|
|
18558
|
+
const snippet = body.length > 500 ? `${body.slice(0, 500)}...` : body;
|
|
18559
|
+
return `${prefix}: ${snippet}`;
|
|
18560
|
+
}
|
|
18561
|
+
|
|
18562
|
+
// src/lib/wallet-default.ts
|
|
18563
|
+
var cache = null;
|
|
18564
|
+
async function loadWallets(auth) {
|
|
18565
|
+
if (cache)
|
|
18566
|
+
return cache;
|
|
18567
|
+
const data = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets`);
|
|
18568
|
+
cache = data.wallets ?? [];
|
|
18569
|
+
return cache;
|
|
18570
|
+
}
|
|
18571
|
+
async function resolveWalletAddress(auth, explicit, preferredChain = "solana") {
|
|
18572
|
+
if (explicit)
|
|
18573
|
+
return explicit;
|
|
18574
|
+
const wallets = await loadWallets(auth);
|
|
18575
|
+
const match = wallets.find((w) => w.status === "active" && w.chain === preferredChain);
|
|
18576
|
+
if (match)
|
|
18577
|
+
return match.wallet_address;
|
|
18578
|
+
const anyActive = wallets.find((w) => w.status === "active");
|
|
18579
|
+
if (anyActive && !explicit) {
|
|
18580
|
+
throw new Error(`No active ${preferredChain} wallet found. Run \`amiko wallets create --chain ${preferredChain}\` or pass --wallet <address> explicitly.`);
|
|
18581
|
+
}
|
|
18582
|
+
throw new Error(`No wallets found for this agent. Run \`amiko wallets create --chain ${preferredChain}\` first.`);
|
|
18583
|
+
}
|
|
18584
|
+
|
|
18491
18585
|
// src/lib/across.ts
|
|
18492
18586
|
function getBridgeBase() {
|
|
18493
18587
|
const config = loadConfig();
|
|
@@ -18639,7 +18733,7 @@ var DEFAULT_ORIGIN = CHAINS.solana;
|
|
|
18639
18733
|
var DEFAULT_DESTINATION = CHAINS.tempo;
|
|
18640
18734
|
function registerBridgeCommand(program2) {
|
|
18641
18735
|
const cmd = program2.command("bridge").description("Bridge USDC across chains via Across Protocol");
|
|
18642
|
-
cmd.command("quote").description("Get a bridge quote for USDC transfer").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").action(async (amountStr, opts) => {
|
|
18736
|
+
cmd.command("quote").description("Get a bridge quote for USDC transfer").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 (required for Solana ↔ EVM)").option("--depositor <address>", "Depositor address on origin chain (defaults to your wallet on that chain)").action(async (amountStr, opts) => {
|
|
18643
18737
|
const spinner = ora("Fetching bridge quote...").start();
|
|
18644
18738
|
try {
|
|
18645
18739
|
const originChainId = resolveChainId(opts.from);
|
|
@@ -18647,10 +18741,14 @@ function registerBridgeCommand(program2) {
|
|
|
18647
18741
|
const inputToken = getUsdcAddress(originChainId);
|
|
18648
18742
|
const outputToken = getUsdcAddress(destChainId);
|
|
18649
18743
|
const amount = parseUsdcAmount(amountStr);
|
|
18650
|
-
const
|
|
18651
|
-
|
|
18744
|
+
const preferredChain = originChainId === CHAINS.solana ? "solana" : "base";
|
|
18745
|
+
let depositor;
|
|
18746
|
+
try {
|
|
18747
|
+
const auth = requireAuth();
|
|
18748
|
+
depositor = await resolveWalletAddress(auth, opts.depositor, preferredChain);
|
|
18749
|
+
} catch (e) {
|
|
18652
18750
|
spinner.stop();
|
|
18653
|
-
console.error(error(
|
|
18751
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
18654
18752
|
process.exit(1);
|
|
18655
18753
|
}
|
|
18656
18754
|
const isCrossEcosystem = originChainId === CHAINS.solana !== (destChainId === CHAINS.solana);
|
|
@@ -18698,8 +18796,8 @@ function registerBridgeCommand(program2) {
|
|
|
18698
18796
|
}
|
|
18699
18797
|
if (quote.swapTx) {
|
|
18700
18798
|
console.log("");
|
|
18701
|
-
console.log(dim('Transaction ready. Run "amiko bridge send" to execute.'));
|
|
18702
|
-
console.log(dim(` amiko bridge send ${amountStr} --from ${opts.from} --to ${opts.to}`));
|
|
18799
|
+
console.log(dim('Transaction ready. Run "amiko wallets bridge send" to execute.'));
|
|
18800
|
+
console.log(dim(` amiko wallets bridge send ${amountStr} --from ${opts.from} --to ${opts.to}${opts.depositor ? ` --depositor ${opts.depositor}` : ""}${opts.recipient ? ` --recipient ${opts.recipient}` : ""}`));
|
|
18703
18801
|
}
|
|
18704
18802
|
} catch (err) {
|
|
18705
18803
|
spinner.stop();
|
|
@@ -18707,7 +18805,7 @@ function registerBridgeCommand(program2) {
|
|
|
18707
18805
|
process.exit(1);
|
|
18708
18806
|
}
|
|
18709
18807
|
});
|
|
18710
|
-
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) => {
|
|
18808
|
+
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 (required for Solana ↔ EVM)").option("--depositor <address>", "Depositor address on origin chain (defaults to your wallet on that chain)").option("--raw", "Output raw transaction JSON for manual signing").option("--yes", "Skip confirmation (only after the user has approved)").action(async (amountStr, opts) => {
|
|
18711
18809
|
const spinner = ora("Preparing bridge transaction...").start();
|
|
18712
18810
|
try {
|
|
18713
18811
|
const originChainId = resolveChainId(opts.from);
|
|
@@ -18715,10 +18813,14 @@ function registerBridgeCommand(program2) {
|
|
|
18715
18813
|
const inputToken = getUsdcAddress(originChainId);
|
|
18716
18814
|
const outputToken = getUsdcAddress(destChainId);
|
|
18717
18815
|
const amount = parseUsdcAmount(amountStr);
|
|
18718
|
-
const
|
|
18719
|
-
|
|
18816
|
+
const preferredChain = originChainId === CHAINS.solana ? "solana" : "base";
|
|
18817
|
+
let depositor;
|
|
18818
|
+
try {
|
|
18819
|
+
const auth = requireAuth();
|
|
18820
|
+
depositor = await resolveWalletAddress(auth, opts.depositor, preferredChain);
|
|
18821
|
+
} catch (e) {
|
|
18720
18822
|
spinner.stop();
|
|
18721
|
-
console.error(error(
|
|
18823
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
18722
18824
|
process.exit(1);
|
|
18723
18825
|
}
|
|
18724
18826
|
const isCrossEcosystem = originChainId === CHAINS.solana !== (destChainId === CHAINS.solana);
|
|
@@ -18752,7 +18854,7 @@ function registerBridgeCommand(program2) {
|
|
|
18752
18854
|
cost: quote.fees?.total ? `${formatUsdcAmount(quote.fees.total.amount)} USDC bridge fee + gas` : "gas + Across fee",
|
|
18753
18855
|
summary: `bridge ${formatUsdcAmount(quote.inputAmount)} USDC ${originName} → ${destName}`,
|
|
18754
18856
|
yes: opts.yes,
|
|
18755
|
-
commandExample: `amiko bridge send ${amountStr} --from ${opts.from} --to ${opts.to}`
|
|
18857
|
+
commandExample: `amiko wallets bridge send ${amountStr} --from ${opts.from} --to ${opts.to}`
|
|
18756
18858
|
});
|
|
18757
18859
|
}
|
|
18758
18860
|
if (opts.raw) {
|
|
@@ -18831,7 +18933,7 @@ function registerBridgeCommand(program2) {
|
|
|
18831
18933
|
console.log(dim(output.trim()));
|
|
18832
18934
|
console.log("");
|
|
18833
18935
|
console.log(dim("Track status:"));
|
|
18834
|
-
console.log(dim(` amiko bridge status <txHash> --chain ${originChainId}`));
|
|
18936
|
+
console.log(dim(` amiko wallets bridge status <txHash> --chain ${originChainId}`));
|
|
18835
18937
|
} catch (err) {
|
|
18836
18938
|
bridgeSpinner.fail("Bridge transaction failed");
|
|
18837
18939
|
console.error(error(err instanceof Error ? err.message : "Transaction failed"));
|
|
@@ -18978,94 +19080,13 @@ function registerBridgeCommand(program2) {
|
|
|
18978
19080
|
// src/commands/credits.ts
|
|
18979
19081
|
import readline2 from "node:readline";
|
|
18980
19082
|
|
|
18981
|
-
// src/lib/amiko-web.ts
|
|
18982
|
-
var DEFAULT_PLATFORM_URL = "https://platform.heyamiko.com";
|
|
18983
|
-
function baseUrl(auth) {
|
|
18984
|
-
const url = auth.platformUrl || DEFAULT_PLATFORM_URL;
|
|
18985
|
-
return url.replace(/\/$/, "");
|
|
18986
|
-
}
|
|
18987
|
-
function authHeader(auth) {
|
|
18988
|
-
if (auth.twinToken)
|
|
18989
|
-
return `Bearer ${auth.twinToken}`;
|
|
18990
|
-
throw new Error("No twin token found. Place an .amiko.json file with amikoTwinToken in the current directory or any parent.");
|
|
18991
|
-
}
|
|
18992
|
-
async function amikoWebFetch(auth, path, opts = {}) {
|
|
18993
|
-
const url = new URL(`${baseUrl(auth)}${path}`);
|
|
18994
|
-
if (opts.query) {
|
|
18995
|
-
for (const [k, v] of Object.entries(opts.query)) {
|
|
18996
|
-
if (v !== undefined && v !== null)
|
|
18997
|
-
url.searchParams.set(k, String(v));
|
|
18998
|
-
}
|
|
18999
|
-
}
|
|
19000
|
-
const headers = {
|
|
19001
|
-
Authorization: authHeader(auth),
|
|
19002
|
-
...opts.headers
|
|
19003
|
-
};
|
|
19004
|
-
let body;
|
|
19005
|
-
if (opts.multipart) {
|
|
19006
|
-
body = opts.multipart;
|
|
19007
|
-
} else if (opts.rawBody) {
|
|
19008
|
-
body = opts.rawBody;
|
|
19009
|
-
if (opts.rawContentType)
|
|
19010
|
-
headers["Content-Type"] = opts.rawContentType;
|
|
19011
|
-
} else if (opts.body) {
|
|
19012
|
-
body = JSON.stringify(opts.body);
|
|
19013
|
-
headers["Content-Type"] = "application/json";
|
|
19014
|
-
}
|
|
19015
|
-
const controller = new AbortController;
|
|
19016
|
-
const timeoutMs = opts.timeoutMs ?? 30000;
|
|
19017
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
19018
|
-
let res;
|
|
19019
|
-
try {
|
|
19020
|
-
res = await fetch(url, {
|
|
19021
|
-
method: opts.method ?? "GET",
|
|
19022
|
-
headers,
|
|
19023
|
-
body,
|
|
19024
|
-
signal: controller.signal
|
|
19025
|
-
});
|
|
19026
|
-
} finally {
|
|
19027
|
-
clearTimeout(timer);
|
|
19028
|
-
}
|
|
19029
|
-
if (!res.ok) {
|
|
19030
|
-
const text = await res.text().catch(() => "");
|
|
19031
|
-
const err = new Error(formatError(res.status, text, path));
|
|
19032
|
-
err.status = res.status;
|
|
19033
|
-
err.body = text;
|
|
19034
|
-
throw err;
|
|
19035
|
-
}
|
|
19036
|
-
const ctype = res.headers.get("content-type") || "";
|
|
19037
|
-
if (ctype.includes("application/json")) {
|
|
19038
|
-
return await res.json();
|
|
19039
|
-
}
|
|
19040
|
-
return await res.text();
|
|
19041
|
-
}
|
|
19042
|
-
function formatError(status, body, path) {
|
|
19043
|
-
const prefix = `${status} ${path}`;
|
|
19044
|
-
if (status === 401) {
|
|
19045
|
-
return `${prefix}: unauthorized. The stored token is invalid or expired; re-link this device to Amiko.`;
|
|
19046
|
-
}
|
|
19047
|
-
if (status === 403) {
|
|
19048
|
-
return `${prefix}: forbidden. The current auth context does not have access to this resource.`;
|
|
19049
|
-
}
|
|
19050
|
-
if (!body)
|
|
19051
|
-
return prefix;
|
|
19052
|
-
const snippet = body.length > 500 ? `${body.slice(0, 500)}...` : body;
|
|
19053
|
-
return `${prefix}: ${snippet}`;
|
|
19054
|
-
}
|
|
19055
|
-
|
|
19056
19083
|
// src/lib/balance.ts
|
|
19057
19084
|
async function fetchCreditsBalance(auth) {
|
|
19058
19085
|
if (!auth.twinToken)
|
|
19059
19086
|
return null;
|
|
19060
|
-
const base = (auth.billingBase || "https://billing.heyamiko.com").replace(/\/$/, "");
|
|
19061
19087
|
try {
|
|
19062
|
-
const
|
|
19063
|
-
|
|
19064
|
-
});
|
|
19065
|
-
if (!res.ok)
|
|
19066
|
-
return null;
|
|
19067
|
-
const data = await res.json();
|
|
19068
|
-
const raw = data.displayBalance ?? Number(data.credits?.balance ?? 0);
|
|
19088
|
+
const data = await amikoWebFetch(auth, `/api/proxy/service/api/credits`);
|
|
19089
|
+
const raw = data.displayBalance;
|
|
19069
19090
|
return typeof raw === "number" && isFinite(raw) ? Math.round(raw) : null;
|
|
19070
19091
|
} catch {
|
|
19071
19092
|
return null;
|
|
@@ -19077,8 +19098,7 @@ async function printBalanceRemaining(auth) {
|
|
|
19077
19098
|
console.log(dim("Balance: (could not fetch)"));
|
|
19078
19099
|
return;
|
|
19079
19100
|
}
|
|
19080
|
-
|
|
19081
|
-
console.log(label("Balance", `${balance.toLocaleString()} credits (~$${usd2})`));
|
|
19101
|
+
console.log(label("Balance", `${balance.toLocaleString()} credits`));
|
|
19082
19102
|
}
|
|
19083
19103
|
|
|
19084
19104
|
// src/lib/mpp-topup.ts
|
|
@@ -19170,8 +19190,7 @@ function registerCreditsCommand(program2) {
|
|
|
19170
19190
|
console.log(dim(" Could not fetch credit balance"));
|
|
19171
19191
|
return;
|
|
19172
19192
|
}
|
|
19173
|
-
|
|
19174
|
-
console.log(label("Balance", `${source_default.bold(balance.toLocaleString())} credits (~$${usd2})`));
|
|
19193
|
+
console.log(label("Balance", source_default.bold(`${balance.toLocaleString()} credits`)));
|
|
19175
19194
|
});
|
|
19176
19195
|
credits.command("topup [amount]").description("Top up credits by spending tokens from your agent wallet. <amount> is in credits (10,000 = $1.00). Use --usd <n> to specify dollars, or --spend <n> to specify a token amount (e.g. 1 SOL worth).").option("--token <TOKEN>", "Token to use for top-up").option("--chain <CHAIN>", "Chain to use for top-up").option("--wallet <ADDR>", "Wallet address to use").option("--method <METHOD>", "Payment method: auto, crossmint, mpp", "auto").option("--key-id <ID>", "Platform API key ID (required for --method mpp)").option("--usd <amount>", "Amount in USD instead of credits (e.g. --usd 1 = 10,000 credits)").option("--spend <amount>", "Spend this many units of --token and convert to credits at current price").option("--yes", "Skip the interactive Proceed? prompt").action(async (amountStr, options) => {
|
|
19177
19196
|
const inputs = [amountStr, options.usd, options.spend].filter((v) => v != null && v !== "");
|
|
@@ -19307,6 +19326,7 @@ function registerCreditsCommand(program2) {
|
|
|
19307
19326
|
if (mppResult.credits?.balance)
|
|
19308
19327
|
console.log(label("Balance", String(mppResult.credits.balance)));
|
|
19309
19328
|
console.log(success("Credits topped up via MPP."));
|
|
19329
|
+
console.log(dim("Balance may take a moment to reflect on-chain confirmation — re-run `amiko credits balance` if it looks stale."));
|
|
19310
19330
|
return;
|
|
19311
19331
|
}
|
|
19312
19332
|
console.log(heading("Top-up Summary"));
|
|
@@ -19351,6 +19371,7 @@ function registerCreditsCommand(program2) {
|
|
|
19351
19371
|
}
|
|
19352
19372
|
console.log("");
|
|
19353
19373
|
console.log(success("Credits topped up."));
|
|
19374
|
+
console.log(dim("Balance may take a moment to reflect on-chain confirmation — re-run `amiko credits balance` if it looks stale."));
|
|
19354
19375
|
} catch (e) {
|
|
19355
19376
|
spinner.stop();
|
|
19356
19377
|
console.error(error(e instanceof Error ? e.message : "Top-up failed"));
|
|
@@ -19465,14 +19486,15 @@ function registerSwapCommand(program2) {
|
|
|
19465
19486
|
console.log(label("Route", dim(route)));
|
|
19466
19487
|
}
|
|
19467
19488
|
console.log("");
|
|
19468
|
-
console.log(dim(`To execute: amiko swap send ${amountStr} ${fromToken} ${toToken}`
|
|
19489
|
+
console.log(dim(`To execute: amiko wallets swap send ${amountStr} ${fromToken} ${toToken}` + `
|
|
19490
|
+
(uses your default Solana wallet; pass --wallet <address> to override)`));
|
|
19469
19491
|
} catch (err) {
|
|
19470
19492
|
spinner.stop();
|
|
19471
19493
|
console.error(error(err instanceof Error ? err.message : "Failed to get quote"));
|
|
19472
19494
|
process.exit(1);
|
|
19473
19495
|
}
|
|
19474
19496
|
});
|
|
19475
|
-
cmd.command("send").description("Execute a token swap on Solana via Crossmint wallet").argument("<amount>", "Amount to swap (e.g., 5, 0.1)").argument("<from>", "Input token (sol, usdc, usdt, amiko, bonk, or mint address)").argument("<to>", "Output token (sol, usdc, usdt, amiko, bonk, or mint address)").option("--wallet <address>", "
|
|
19497
|
+
cmd.command("send").description("Execute a token swap on Solana via Crossmint wallet").argument("<amount>", "Amount to swap (e.g., 5, 0.1)").argument("<from>", "Input token (sol, usdc, usdt, amiko, bonk, or mint address)").argument("<to>", "Output token (sol, usdc, usdt, amiko, bonk, or mint address)").option("--wallet <address>", "Solana wallet to swap from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if none)").option("--slippage <bps>", "Slippage tolerance in basis points", "50").option("--yes", "Skip confirmation").action(async (amountStr, fromToken, toToken, opts) => {
|
|
19476
19498
|
try {
|
|
19477
19499
|
let auth;
|
|
19478
19500
|
try {
|
|
@@ -19481,9 +19503,11 @@ function registerSwapCommand(program2) {
|
|
|
19481
19503
|
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
19482
19504
|
process.exit(1);
|
|
19483
19505
|
}
|
|
19484
|
-
|
|
19485
|
-
|
|
19486
|
-
|
|
19506
|
+
let wallet;
|
|
19507
|
+
try {
|
|
19508
|
+
wallet = await resolveWalletAddress(auth, opts.wallet, "solana");
|
|
19509
|
+
} catch (e) {
|
|
19510
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
19487
19511
|
process.exit(1);
|
|
19488
19512
|
}
|
|
19489
19513
|
const input = resolveToken(fromToken);
|
|
@@ -19514,7 +19538,7 @@ function registerSwapCommand(program2) {
|
|
|
19514
19538
|
cost: "Solana gas + 10bps platform fee",
|
|
19515
19539
|
summary: `swap ${amountStr} ${fromToken.toUpperCase()} → ~${(Number(quote.outAmount) / 10 ** output.decimals).toFixed(6)} ${output.symbol}`,
|
|
19516
19540
|
yes: opts.yes,
|
|
19517
|
-
commandExample: `amiko swap send ${amountStr} ${fromToken} ${toToken}`
|
|
19541
|
+
commandExample: `amiko wallets swap send ${amountStr} ${fromToken} ${toToken}`
|
|
19518
19542
|
});
|
|
19519
19543
|
const swapSpinner = ora("Executing swap via platform...").start();
|
|
19520
19544
|
let swapData;
|
|
@@ -19561,7 +19585,7 @@ function registerSwapCommand(program2) {
|
|
|
19561
19585
|
console.log(` ${source_default.cyan(t.symbol.padEnd(10))} ${t.name.padEnd(25)} ${dim(truncAddr(t.address))}`);
|
|
19562
19586
|
}
|
|
19563
19587
|
console.log("");
|
|
19564
|
-
console.log(dim("Use symbol or mint address: amiko swap quote 5 usdt usdc"));
|
|
19588
|
+
console.log(dim("Use symbol or mint address: amiko wallets swap quote 5 usdt usdc"));
|
|
19565
19589
|
} catch (err) {
|
|
19566
19590
|
spinner.stop();
|
|
19567
19591
|
console.error(error(err instanceof Error ? err.message : "Failed to fetch tokens"));
|
|
@@ -19582,6 +19606,71 @@ function detectPackageManager() {
|
|
|
19582
19606
|
return "npm";
|
|
19583
19607
|
}
|
|
19584
19608
|
}
|
|
19609
|
+
function isPrerelease(v) {
|
|
19610
|
+
return v.includes("-");
|
|
19611
|
+
}
|
|
19612
|
+
function compareSemver(a, b) {
|
|
19613
|
+
const [aMain, aPre] = a.split("-", 2);
|
|
19614
|
+
const [bMain, bPre] = b.split("-", 2);
|
|
19615
|
+
const an = aMain.split(".").map(Number);
|
|
19616
|
+
const bn = bMain.split(".").map(Number);
|
|
19617
|
+
for (let i = 0;i < 3; i++) {
|
|
19618
|
+
if ((an[i] ?? 0) !== (bn[i] ?? 0))
|
|
19619
|
+
return (an[i] ?? 0) > (bn[i] ?? 0) ? 1 : -1;
|
|
19620
|
+
}
|
|
19621
|
+
if (!aPre && !bPre)
|
|
19622
|
+
return 0;
|
|
19623
|
+
if (!aPre)
|
|
19624
|
+
return 1;
|
|
19625
|
+
if (!bPre)
|
|
19626
|
+
return -1;
|
|
19627
|
+
const ap = aPre.split(".");
|
|
19628
|
+
const bp = bPre.split(".");
|
|
19629
|
+
for (let i = 0;i < Math.max(ap.length, bp.length); i++) {
|
|
19630
|
+
const x = ap[i];
|
|
19631
|
+
const y = bp[i];
|
|
19632
|
+
if (x === undefined)
|
|
19633
|
+
return -1;
|
|
19634
|
+
if (y === undefined)
|
|
19635
|
+
return 1;
|
|
19636
|
+
const xn = /^\d+$/.test(x) ? Number(x) : NaN;
|
|
19637
|
+
const yn = /^\d+$/.test(y) ? Number(y) : NaN;
|
|
19638
|
+
if (!isNaN(xn) && !isNaN(yn)) {
|
|
19639
|
+
if (xn !== yn)
|
|
19640
|
+
return xn > yn ? 1 : -1;
|
|
19641
|
+
} else if (!isNaN(xn)) {
|
|
19642
|
+
return -1;
|
|
19643
|
+
} else if (!isNaN(yn)) {
|
|
19644
|
+
return 1;
|
|
19645
|
+
} else if (x !== y) {
|
|
19646
|
+
return x > y ? 1 : -1;
|
|
19647
|
+
}
|
|
19648
|
+
}
|
|
19649
|
+
return 0;
|
|
19650
|
+
}
|
|
19651
|
+
async function fetchDistTags(pkg) {
|
|
19652
|
+
const url2 = `https://registry.npmjs.org/-/package/${encodeURIComponent(pkg)}/dist-tags`;
|
|
19653
|
+
const res = await fetch(url2);
|
|
19654
|
+
if (!res.ok)
|
|
19655
|
+
throw new Error(`registry responded ${res.status}`);
|
|
19656
|
+
return await res.json();
|
|
19657
|
+
}
|
|
19658
|
+
async function resolveTargetVersion(pkg, currentVersion) {
|
|
19659
|
+
if (!isPrerelease(currentVersion)) {
|
|
19660
|
+
return { version: "latest", channel: "latest" };
|
|
19661
|
+
}
|
|
19662
|
+
const tags = await fetchDistTags(pkg);
|
|
19663
|
+
const latest = tags.latest;
|
|
19664
|
+
const beta = tags.beta;
|
|
19665
|
+
if (latest && beta) {
|
|
19666
|
+
return compareSemver(latest, beta) >= 0 ? { version: latest, channel: "latest" } : { version: beta, channel: "beta" };
|
|
19667
|
+
}
|
|
19668
|
+
if (beta)
|
|
19669
|
+
return { version: beta, channel: "beta" };
|
|
19670
|
+
if (latest)
|
|
19671
|
+
return { version: latest, channel: "latest" };
|
|
19672
|
+
return { version: "latest", channel: "latest" };
|
|
19673
|
+
}
|
|
19585
19674
|
var DATA_CLI = "/data/.amiko-cli";
|
|
19586
19675
|
var NPM_GLOBAL_CANDIDATES = [
|
|
19587
19676
|
"/usr/local/lib/node_modules/@heyamiko/amiko-cli",
|
|
@@ -19627,17 +19716,21 @@ function registerUpdateCommand(program2) {
|
|
|
19627
19716
|
console.log(heading("Update"));
|
|
19628
19717
|
console.log(label("Current", `v${currentVersion}`));
|
|
19629
19718
|
console.log(label("Package manager", pm));
|
|
19719
|
+
let target;
|
|
19720
|
+
try {
|
|
19721
|
+
target = await resolveTargetVersion(pkg, currentVersion);
|
|
19722
|
+
} catch {
|
|
19723
|
+
target = { version: "latest", channel: "latest" };
|
|
19724
|
+
}
|
|
19725
|
+
const installSpec = `${pkg}@${target.version}`;
|
|
19726
|
+
console.log(label("Target", target.version === "latest" ? "latest" : `${target.version} (${target.channel})`));
|
|
19630
19727
|
console.log("");
|
|
19631
|
-
const spinner = ora(
|
|
19728
|
+
const spinner = ora(`Installing ${installSpec}...`).start();
|
|
19632
19729
|
try {
|
|
19633
19730
|
if (pm === "bun") {
|
|
19634
|
-
execFileSync2("bun", ["install", "-g",
|
|
19635
|
-
stdio: "pipe"
|
|
19636
|
-
});
|
|
19731
|
+
execFileSync2("bun", ["install", "-g", installSpec], { stdio: "pipe" });
|
|
19637
19732
|
} else {
|
|
19638
|
-
execFileSync2("npm", ["install", "-g",
|
|
19639
|
-
stdio: "pipe"
|
|
19640
|
-
});
|
|
19733
|
+
execFileSync2("npm", ["install", "-g", installSpec], { stdio: "pipe" });
|
|
19641
19734
|
}
|
|
19642
19735
|
spinner.stop();
|
|
19643
19736
|
let syncedTwin = false;
|
|
@@ -19667,7 +19760,7 @@ function registerUpdateCommand(program2) {
|
|
|
19667
19760
|
console.error(error("Auto-update failed."));
|
|
19668
19761
|
console.log("");
|
|
19669
19762
|
console.log(dim("Try manually:"));
|
|
19670
|
-
console.log(dim(` ${pm} install -g ${
|
|
19763
|
+
console.log(dim(` ${pm} install -g ${installSpec}`));
|
|
19671
19764
|
process.exit(1);
|
|
19672
19765
|
}
|
|
19673
19766
|
});
|
|
@@ -19691,12 +19784,12 @@ async function reportHttpError(res, label2) {
|
|
|
19691
19784
|
// src/commands/search.ts
|
|
19692
19785
|
var TREASURY = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
19693
19786
|
function registerSearchCommand(program2) {
|
|
19694
|
-
program2.command("search <query>").description("X Search — pays 1 AMIKO token per search").option("--raw", "Output raw JSON").option("--token <token>", "Payment token (AMIKO, USDC, SOL)", "AMIKO").option("--wallet <address>", "Solana wallet
|
|
19787
|
+
program2.command("search <query>").description("X Search — pays 1 AMIKO token per search").option("--raw", "Output raw JSON").option("--token <token>", "Payment token (AMIKO, USDC, SOL)", "AMIKO").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if you don't have one)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
19695
19788
|
await requireApproval({
|
|
19696
19789
|
cost: `1 ${opts.token || "AMIKO"}`,
|
|
19697
19790
|
summary: `X/Twitter search: ${query.slice(0, 80)}${query.length > 80 ? "…" : ""}`,
|
|
19698
19791
|
yes: opts.yes,
|
|
19699
|
-
commandExample: `amiko search ${JSON.stringify(query)}${opts.token && opts.token !== "AMIKO" ? ` --token ${opts.token}` : ""}`
|
|
19792
|
+
commandExample: `amiko markets search ${JSON.stringify(query)}${opts.token && opts.token !== "AMIKO" ? ` --token ${opts.token}` : ""}`
|
|
19700
19793
|
});
|
|
19701
19794
|
const spinner = ora("X Search...").start();
|
|
19702
19795
|
try {
|
|
@@ -19713,10 +19806,12 @@ function registerSearchCommand(program2) {
|
|
|
19713
19806
|
const token = opts.token || "AMIKO";
|
|
19714
19807
|
const chain = "solana";
|
|
19715
19808
|
const amount2 = token === "AMIKO" ? "1" : "0.01";
|
|
19716
|
-
|
|
19717
|
-
|
|
19809
|
+
let wallet;
|
|
19810
|
+
try {
|
|
19811
|
+
wallet = await resolveWalletAddress(auth, opts.wallet, "solana");
|
|
19812
|
+
} catch (e) {
|
|
19718
19813
|
spinner.stop();
|
|
19719
|
-
console.error(error(
|
|
19814
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
19720
19815
|
process.exit(1);
|
|
19721
19816
|
}
|
|
19722
19817
|
spinner.text = `Paying ${amount2} ${token} (${chain})...`;
|
|
@@ -19790,12 +19885,12 @@ function registerSearchCommand(program2) {
|
|
|
19790
19885
|
// src/commands/image.ts
|
|
19791
19886
|
var TREASURY2 = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
19792
19887
|
function registerImageCommand(program2) {
|
|
19793
|
-
program2.command("image <prompt>").alias("img").description("Generate an image — costs 5 AMIKO").option("--size <size>", "Image size: 1024x1024, 1024x1792, 1792x1024", "1024x1024").option("--quality <q>", "Quality: auto, low, medium, high (gpt-image-1) or standard, hd (dall-e-3)", "auto").option("--model <model>", "Model: gpt-image-1 or dall-e-3", "gpt-image-1").option("--background <bg>", "Background: transparent, opaque, auto (gpt-image-1 only)").option("--format <fmt>", "Output: png, webp, jpeg (gpt-image-1 only)", "png").option("--wallet <address>", "Solana wallet
|
|
19888
|
+
program2.command("image <prompt>").alias("img").description("Generate an image — costs 5 AMIKO").option("--size <size>", "Image size: 1024x1024, 1024x1792, 1792x1024", "1024x1024").option("--quality <q>", "Quality: auto, low, medium, high (gpt-image-1) or standard, hd (dall-e-3)", "auto").option("--model <model>", "Model: gpt-image-1 or dall-e-3", "gpt-image-1").option("--background <bg>", "Background: transparent, opaque, auto (gpt-image-1 only)").option("--format <fmt>", "Output: png, webp, jpeg (gpt-image-1 only)", "png").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if you don't have one)").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
|
|
19794
19889
|
await requireApproval({
|
|
19795
19890
|
cost: "5 AMIKO",
|
|
19796
19891
|
summary: `Generate image: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
|
|
19797
19892
|
yes: opts.yes,
|
|
19798
|
-
commandExample: `amiko image ${JSON.stringify(prompt)}`
|
|
19893
|
+
commandExample: `amiko markets image ${JSON.stringify(prompt)}`
|
|
19799
19894
|
});
|
|
19800
19895
|
const isTTY = process.stderr.isTTY;
|
|
19801
19896
|
const spinner = isTTY ? ora("Generating image...").start() : null;
|
|
@@ -19836,10 +19931,12 @@ function registerImageCommand(program2) {
|
|
|
19836
19931
|
process.exit(1);
|
|
19837
19932
|
}
|
|
19838
19933
|
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
19839
|
-
|
|
19840
|
-
|
|
19934
|
+
let wallet;
|
|
19935
|
+
try {
|
|
19936
|
+
wallet = await resolveWalletAddress(auth, opts.wallet, "solana");
|
|
19937
|
+
} catch (e) {
|
|
19841
19938
|
stopProgress();
|
|
19842
|
-
console.error(error(
|
|
19939
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
19843
19940
|
process.exit(1);
|
|
19844
19941
|
}
|
|
19845
19942
|
setStatus("Paying 5 AMIKO...");
|
|
@@ -19899,7 +19996,7 @@ function registerImageCommand(program2) {
|
|
|
19899
19996
|
console.log(label("URL", img.url));
|
|
19900
19997
|
} else if (img.b64_json) {
|
|
19901
19998
|
console.log(label("Format", "base64 (inline image data)"));
|
|
19902
|
-
console.log(dim(` ${img.b64_json.length.toLocaleString()} chars — save with: amiko image "..." --raw | jq -r '.images[0].b64_json' | base64 -d > image.png`));
|
|
19999
|
+
console.log(dim(` ${img.b64_json.length.toLocaleString()} chars — save with: amiko markets image "..." --raw | jq -r '.images[0].b64_json' | base64 -d > image.png`));
|
|
19903
20000
|
}
|
|
19904
20001
|
if (img.revised_prompt && img.revised_prompt !== prompt) {
|
|
19905
20002
|
console.log(label("Revised", dim(img.revised_prompt)));
|
|
@@ -19929,12 +20026,12 @@ async function payAmiko(auth, wallet, amount2) {
|
|
|
19929
20026
|
}
|
|
19930
20027
|
function registerAmazonCommand(program2) {
|
|
19931
20028
|
const cmd = program2.command("amazon").description("Search and buy products on Amazon — paid with AMIKO");
|
|
19932
|
-
cmd.command("search <query>").description("Search Amazon products — 1 AMIKO").option("--limit <n>", "Number of results", "5").option("--wallet <address>", "Solana wallet
|
|
20029
|
+
cmd.command("search <query>").description("Search Amazon products — 1 AMIKO").option("--limit <n>", "Number of results", "5").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if you don't have one)").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
19933
20030
|
await requireApproval({
|
|
19934
20031
|
cost: "1 AMIKO",
|
|
19935
20032
|
summary: `Amazon product search: ${query.slice(0, 80)}${query.length > 80 ? "…" : ""}`,
|
|
19936
20033
|
yes: opts.yes,
|
|
19937
|
-
commandExample: `amiko amazon search ${JSON.stringify(query)}`
|
|
20034
|
+
commandExample: `amiko markets amazon search ${JSON.stringify(query)}`
|
|
19938
20035
|
});
|
|
19939
20036
|
const spinner = ora("Searching Amazon...").start();
|
|
19940
20037
|
try {
|
|
@@ -19948,10 +20045,12 @@ function registerAmazonCommand(program2) {
|
|
|
19948
20045
|
process.exit(1);
|
|
19949
20046
|
}
|
|
19950
20047
|
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
19951
|
-
|
|
19952
|
-
|
|
20048
|
+
let wallet;
|
|
20049
|
+
try {
|
|
20050
|
+
wallet = await resolveWalletAddress(auth, opts.wallet, "solana");
|
|
20051
|
+
} catch (e) {
|
|
19953
20052
|
spinner.stop();
|
|
19954
|
-
console.error(error(
|
|
20053
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
19955
20054
|
process.exit(1);
|
|
19956
20055
|
}
|
|
19957
20056
|
spinner.text = "Paying 1 AMIKO...";
|
|
@@ -20121,12 +20220,12 @@ async function payAndCall(mppBase2, method, path2, auth, wallet, amountOrAuto, b
|
|
|
20121
20220
|
}
|
|
20122
20221
|
function registerServicesCommand(program2) {
|
|
20123
20222
|
const svc = program2.command("service").alias("svc").description("Call any MPP service — pays with AMIKO tokens");
|
|
20124
|
-
svc.command("tts <voiceId> <text>").description("Text-to-speech — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet
|
|
20223
|
+
svc.command("tts <voiceId> <text>").description("Text-to-speech — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if none)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (voiceId, text, opts) => {
|
|
20125
20224
|
await requireApproval({
|
|
20126
20225
|
cost: "1 AMIKO",
|
|
20127
20226
|
summary: `Text-to-speech (voice ${voiceId}): "${text.slice(0, 60)}${text.length > 60 ? "…" : ""}"`,
|
|
20128
20227
|
yes: opts.yes,
|
|
20129
|
-
commandExample: `amiko service tts ${voiceId} ${JSON.stringify(text)}`
|
|
20228
|
+
commandExample: `amiko markets service tts ${voiceId} ${JSON.stringify(text)}`
|
|
20130
20229
|
});
|
|
20131
20230
|
await callService({
|
|
20132
20231
|
name: "Text-to-Speech",
|
|
@@ -20137,12 +20236,12 @@ function registerServicesCommand(program2) {
|
|
|
20137
20236
|
opts
|
|
20138
20237
|
});
|
|
20139
20238
|
});
|
|
20140
|
-
svc.command("stt <audioUrl>").description("Speech-to-text — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet
|
|
20239
|
+
svc.command("stt <audioUrl>").description("Speech-to-text — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if none)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (audioUrl, opts) => {
|
|
20141
20240
|
await requireApproval({
|
|
20142
20241
|
cost: "1 AMIKO",
|
|
20143
20242
|
summary: `Speech-to-text on ${audioUrl}`,
|
|
20144
20243
|
yes: opts.yes,
|
|
20145
|
-
commandExample: `amiko service stt ${JSON.stringify(audioUrl)}`
|
|
20244
|
+
commandExample: `amiko markets service stt ${JSON.stringify(audioUrl)}`
|
|
20146
20245
|
});
|
|
20147
20246
|
await callService({
|
|
20148
20247
|
name: "Speech-to-Text",
|
|
@@ -20171,12 +20270,12 @@ function registerServicesCommand(program2) {
|
|
|
20171
20270
|
console.log(JSON.stringify(data, null, 2));
|
|
20172
20271
|
}
|
|
20173
20272
|
});
|
|
20174
|
-
svc.command("chat <message>").description("AI chat — 1 AMIKO").option("--model <model>", "Model to use").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet
|
|
20273
|
+
svc.command("chat <message>").description("AI chat — 1 AMIKO").option("--model <model>", "Model to use").option("--raw", "Output raw response").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if none)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (message, opts) => {
|
|
20175
20274
|
await requireApproval({
|
|
20176
20275
|
cost: "1 AMIKO",
|
|
20177
20276
|
summary: `AI chat${opts.model ? ` (model ${opts.model})` : ""}: "${message.slice(0, 60)}${message.length > 60 ? "…" : ""}"`,
|
|
20178
20277
|
yes: opts.yes,
|
|
20179
|
-
commandExample: `amiko service chat ${JSON.stringify(message)}${opts.model ? ` --model ${opts.model}` : ""}`
|
|
20278
|
+
commandExample: `amiko markets service chat ${JSON.stringify(message)}${opts.model ? ` --model ${opts.model}` : ""}`
|
|
20180
20279
|
});
|
|
20181
20280
|
const body = { message };
|
|
20182
20281
|
if (opts.model)
|
|
@@ -20190,13 +20289,13 @@ function registerServicesCommand(program2) {
|
|
|
20190
20289
|
opts
|
|
20191
20290
|
});
|
|
20192
20291
|
});
|
|
20193
|
-
svc.command("call <method> <path> [body]").description("Call any MPP endpoint — pays in AMIKO or USDC on Solana").option("--amiko <amount>", "AMIKO tokens to pay (default: auto-price from USD)").option("--usdc <amount>", "Pay in USDC instead of AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet
|
|
20292
|
+
svc.command("call <method> <path> [body]").description("Call any MPP endpoint — pays in AMIKO or USDC on Solana").option("--amiko <amount>", "AMIKO tokens to pay (default: auto-price from USD)").option("--usdc <amount>", "Pay in USDC instead of AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Wallet to pay from (defaults to your Solana wallet — run `amiko wallets create --chain solana` if none)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (method, path2, bodyStr, opts) => {
|
|
20194
20293
|
const costLabel = opts.usdc ? `${opts.usdc} USDC` : opts.amiko ? `${opts.amiko} AMIKO` : "auto-priced AMIKO (check /v1/ list for endpoint price first)";
|
|
20195
20294
|
await requireApproval({
|
|
20196
20295
|
cost: costLabel,
|
|
20197
20296
|
summary: `${method.toUpperCase()} ${path2}`,
|
|
20198
20297
|
yes: opts.yes,
|
|
20199
|
-
commandExample: `amiko service call ${method.toUpperCase()} ${path2}${bodyStr ? ` ${JSON.stringify(bodyStr)}` : ""}${opts.amiko ? ` --amiko ${opts.amiko}` : ""}${opts.usdc ? ` --usdc ${opts.usdc}` : ""}`
|
|
20298
|
+
commandExample: `amiko markets service call ${method.toUpperCase()} ${path2}${bodyStr ? ` ${JSON.stringify(bodyStr)}` : ""}${opts.amiko ? ` --amiko ${opts.amiko}` : ""}${opts.usdc ? ` --usdc ${opts.usdc}` : ""}`
|
|
20200
20299
|
});
|
|
20201
20300
|
let body;
|
|
20202
20301
|
if (bodyStr) {
|
|
@@ -20255,10 +20354,12 @@ async function callService(params) {
|
|
|
20255
20354
|
process.exit(1);
|
|
20256
20355
|
}
|
|
20257
20356
|
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
20258
|
-
|
|
20259
|
-
|
|
20357
|
+
let wallet;
|
|
20358
|
+
try {
|
|
20359
|
+
wallet = await resolveWalletAddress(auth, params.opts.wallet, "solana");
|
|
20360
|
+
} catch (e) {
|
|
20260
20361
|
spinner.stop();
|
|
20261
|
-
console.error(error(
|
|
20362
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
20262
20363
|
process.exit(1);
|
|
20263
20364
|
}
|
|
20264
20365
|
const token = params.usdc ? "USDC" : "AMIKO";
|
|
@@ -20391,7 +20492,7 @@ function parseBool(raw, flag) {
|
|
|
20391
20492
|
throw new Error(`${flag} must be true or false, got "${raw}"`);
|
|
20392
20493
|
}
|
|
20393
20494
|
function registerTwinCommand(program2) {
|
|
20394
|
-
program2.command("
|
|
20495
|
+
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) => {
|
|
20395
20496
|
if (opts.name === undefined && opts.description === undefined && opts.public === undefined) {
|
|
20396
20497
|
console.error(error("Pass at least one of --name, --description, --public"));
|
|
20397
20498
|
process.exit(1);
|
|
@@ -20426,7 +20527,7 @@ function registerTwinCommand(program2) {
|
|
|
20426
20527
|
action: `Set twin visibility to ${next ? "PUBLIC" : "PRIVATE"}`,
|
|
20427
20528
|
detail: next ? "Anyone on amiko.com will be able to find and chat with this twin." : "The twin will no longer be discoverable.",
|
|
20428
20529
|
yes: opts.yes,
|
|
20429
|
-
commandExample: `amiko twin
|
|
20530
|
+
commandExample: `amiko twin update --public ${next}`
|
|
20430
20531
|
});
|
|
20431
20532
|
}
|
|
20432
20533
|
const spinner = opts.json ? null : ora("Updating twin...").start();
|
|
@@ -20548,6 +20649,18 @@ function detectMime(buffer, name) {
|
|
|
20548
20649
|
}
|
|
20549
20650
|
|
|
20550
20651
|
// src/commands/docs.ts
|
|
20652
|
+
function fmtBytes(n) {
|
|
20653
|
+
if (!n || n <= 0)
|
|
20654
|
+
return "-";
|
|
20655
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
20656
|
+
let v = n;
|
|
20657
|
+
let i = 0;
|
|
20658
|
+
while (v >= 1024 && i < units.length - 1) {
|
|
20659
|
+
v /= 1024;
|
|
20660
|
+
i++;
|
|
20661
|
+
}
|
|
20662
|
+
return `${v.toFixed(v >= 10 ? 0 : 1)} ${units[i]}`;
|
|
20663
|
+
}
|
|
20551
20664
|
function twinFromFlag(opts) {
|
|
20552
20665
|
const config2 = loadConfig();
|
|
20553
20666
|
const auth = resolveAuth();
|
|
@@ -20561,20 +20674,8 @@ function twinFromFlag(opts) {
|
|
|
20561
20674
|
throw e;
|
|
20562
20675
|
}
|
|
20563
20676
|
}
|
|
20564
|
-
function fmtBytes(n) {
|
|
20565
|
-
if (!n || n <= 0)
|
|
20566
|
-
return "-";
|
|
20567
|
-
const units = ["B", "KB", "MB", "GB"];
|
|
20568
|
-
let v = n;
|
|
20569
|
-
let i = 0;
|
|
20570
|
-
while (v >= 1024 && i < units.length - 1) {
|
|
20571
|
-
v /= 1024;
|
|
20572
|
-
i++;
|
|
20573
|
-
}
|
|
20574
|
-
return `${v.toFixed(v >= 10 ? 0 : 1)} ${units[i]}`;
|
|
20575
|
-
}
|
|
20576
20677
|
function registerDocsCommand(program2) {
|
|
20577
|
-
program2.command("
|
|
20678
|
+
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) => {
|
|
20578
20679
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20579
20680
|
const spinner = opts.json ? null : ora("Loading documents...").start();
|
|
20580
20681
|
try {
|
|
@@ -20590,15 +20691,15 @@ function registerDocsCommand(program2) {
|
|
|
20590
20691
|
[
|
|
20591
20692
|
dim("ID"),
|
|
20592
20693
|
dim("NAME"),
|
|
20593
|
-
dim("
|
|
20694
|
+
dim("TYPE"),
|
|
20594
20695
|
dim("STATUS"),
|
|
20595
20696
|
dim("CREATED")
|
|
20596
20697
|
],
|
|
20597
20698
|
...d.docs.map((doc2) => [
|
|
20598
20699
|
doc2.id.slice(0, 8),
|
|
20599
20700
|
doc2.title || doc2.filename,
|
|
20600
|
-
|
|
20601
|
-
doc2.
|
|
20701
|
+
doc2.file_type || "-",
|
|
20702
|
+
doc2.is_processed ? "processed" : doc2.is_parsed ? "parsed" : "pending",
|
|
20602
20703
|
doc2.created_at?.slice(0, 10) || "-"
|
|
20603
20704
|
])
|
|
20604
20705
|
];
|
|
@@ -20610,7 +20711,7 @@ function registerDocsCommand(program2) {
|
|
|
20610
20711
|
process.exit(1);
|
|
20611
20712
|
}
|
|
20612
20713
|
});
|
|
20613
|
-
program2.command("
|
|
20714
|
+
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) => {
|
|
20614
20715
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20615
20716
|
const spinner = opts.json ? null : ora("Reading input...").start();
|
|
20616
20717
|
try {
|
|
@@ -20661,13 +20762,13 @@ function registerDocsCommand(program2) {
|
|
|
20661
20762
|
process.exit(1);
|
|
20662
20763
|
}
|
|
20663
20764
|
});
|
|
20664
|
-
program2.command("
|
|
20765
|
+
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) => {
|
|
20665
20766
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20666
20767
|
await confirmDestructive({
|
|
20667
20768
|
action: `Delete document ${docId}`,
|
|
20668
20769
|
detail: "This will remove the document and its embeddings from the twin's RAG.",
|
|
20669
20770
|
yes: opts.yes,
|
|
20670
|
-
commandExample: `amiko docs
|
|
20771
|
+
commandExample: `amiko docs delete ${docId}`
|
|
20671
20772
|
});
|
|
20672
20773
|
const spinner = opts.json ? null : ora("Deleting document...").start();
|
|
20673
20774
|
try {
|
|
@@ -20680,7 +20781,7 @@ function registerDocsCommand(program2) {
|
|
|
20680
20781
|
process.exit(1);
|
|
20681
20782
|
}
|
|
20682
20783
|
});
|
|
20683
|
-
program2.command("
|
|
20784
|
+
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) => {
|
|
20684
20785
|
const { twinId, auth } = twinFromFlag(opts);
|
|
20685
20786
|
const filename = opts.name ?? (source === "-" ? "stdin" : source.split("/").pop() ?? source);
|
|
20686
20787
|
try {
|
|
@@ -20708,7 +20809,7 @@ function twinFromFlag2(opts) {
|
|
|
20708
20809
|
}
|
|
20709
20810
|
}
|
|
20710
20811
|
function registerVoiceCommand(program2) {
|
|
20711
|
-
program2.command("
|
|
20812
|
+
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) => {
|
|
20712
20813
|
if (opts.description.trim().length < 20) {
|
|
20713
20814
|
console.error(error("--description must be at least 20 characters"));
|
|
20714
20815
|
process.exit(1);
|
|
@@ -20728,7 +20829,7 @@ function registerVoiceCommand(program2) {
|
|
|
20728
20829
|
console.log(label(`#${i + 1} id`, p.generated_voice_id ?? "?"));
|
|
20729
20830
|
}
|
|
20730
20831
|
console.log("");
|
|
20731
|
-
console.log(dim("Pick one with: amiko voice
|
|
20832
|
+
console.log(dim("Pick one with: amiko voice create --sample <id>"));
|
|
20732
20833
|
}, { json: opts.json });
|
|
20733
20834
|
} catch (e) {
|
|
20734
20835
|
spinner?.stop();
|
|
@@ -20736,7 +20837,7 @@ function registerVoiceCommand(program2) {
|
|
|
20736
20837
|
process.exit(1);
|
|
20737
20838
|
}
|
|
20738
20839
|
});
|
|
20739
|
-
program2.command("
|
|
20840
|
+
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) => {
|
|
20740
20841
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20741
20842
|
const spinner = opts.json ? null : ora("Creating voice...").start();
|
|
20742
20843
|
try {
|
|
@@ -20762,7 +20863,7 @@ function registerVoiceCommand(program2) {
|
|
|
20762
20863
|
process.exit(1);
|
|
20763
20864
|
}
|
|
20764
20865
|
});
|
|
20765
|
-
program2.command("
|
|
20866
|
+
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) => {
|
|
20766
20867
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20767
20868
|
const spinner = opts.json ? null : ora("Reading audio...").start();
|
|
20768
20869
|
try {
|
|
@@ -20790,13 +20891,13 @@ function registerVoiceCommand(program2) {
|
|
|
20790
20891
|
process.exit(1);
|
|
20791
20892
|
}
|
|
20792
20893
|
});
|
|
20793
|
-
program2.command("
|
|
20894
|
+
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) => {
|
|
20794
20895
|
const { twinId, auth } = twinFromFlag2(opts);
|
|
20795
20896
|
await confirmDestructive({
|
|
20796
20897
|
action: "Reset voice",
|
|
20797
20898
|
detail: "This removes the custom voice. You can redesign or clone a new one later.",
|
|
20798
20899
|
yes: opts.yes,
|
|
20799
|
-
commandExample: "amiko voice
|
|
20900
|
+
commandExample: "amiko voice reset"
|
|
20800
20901
|
});
|
|
20801
20902
|
const spinner = opts.json ? null : ora("Resetting voice...").start();
|
|
20802
20903
|
try {
|
|
@@ -20813,7 +20914,7 @@ function registerVoiceCommand(program2) {
|
|
|
20813
20914
|
|
|
20814
20915
|
// src/commands/avatar.ts
|
|
20815
20916
|
function registerAvatarCommand(program2) {
|
|
20816
|
-
program2.command("
|
|
20917
|
+
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) => {
|
|
20817
20918
|
const config2 = loadConfig();
|
|
20818
20919
|
const auth = resolveAuth();
|
|
20819
20920
|
let twinId;
|
|
@@ -20830,7 +20931,7 @@ function registerAvatarCommand(program2) {
|
|
|
20830
20931
|
action: "Replace twin avatar",
|
|
20831
20932
|
detail: "The twin's public avatar will change immediately.",
|
|
20832
20933
|
yes: opts.yes,
|
|
20833
|
-
commandExample: `amiko avatar
|
|
20934
|
+
commandExample: `amiko avatar update --file ${opts.file}`
|
|
20834
20935
|
});
|
|
20835
20936
|
const spinner = opts.json ? null : ora("Reading image...").start();
|
|
20836
20937
|
try {
|
|
@@ -20872,27 +20973,27 @@ function registerAvatarCommand(program2) {
|
|
|
20872
20973
|
|
|
20873
20974
|
// src/commands/friends.ts
|
|
20874
20975
|
function registerFriendsCommand(program2) {
|
|
20875
|
-
program2.command("
|
|
20976
|
+
program2.command("list").description("List friends").option("--type <user|twin>", "Filter by friend type").option("--json", "Output as JSON").action(async (opts) => {
|
|
20876
20977
|
const auth = resolveAuth();
|
|
20877
20978
|
const spinner = opts.json ? null : ora("Loading friends...").start();
|
|
20878
20979
|
try {
|
|
20879
20980
|
const data = await amikoWebFetch(auth, "/api/friends", { query: { type: opts.type } });
|
|
20880
20981
|
spinner?.stop();
|
|
20881
20982
|
renderOutput(data, (d) => {
|
|
20882
|
-
const items = d.
|
|
20983
|
+
const items = d.friends ?? [];
|
|
20883
20984
|
if (items.length === 0) {
|
|
20884
20985
|
console.log(dim("No friends."));
|
|
20885
20986
|
return;
|
|
20886
20987
|
}
|
|
20887
20988
|
console.log(heading(`Friends (${items.length})`));
|
|
20888
20989
|
const rows = [
|
|
20889
|
-
[dim("ID"), dim("NAME"), dim("HANDLE"), dim("TYPE"), dim("
|
|
20990
|
+
[dim("ID"), dim("NAME"), dim("HANDLE"), dim("TYPE"), dim("SINCE")],
|
|
20890
20991
|
...items.map((f) => [
|
|
20891
|
-
f.
|
|
20992
|
+
f.friendship_id.slice(0, 8),
|
|
20892
20993
|
f.friend.name ?? "-",
|
|
20893
20994
|
f.friend.handle ?? "-",
|
|
20894
20995
|
f.friend.type,
|
|
20895
|
-
f.
|
|
20996
|
+
f.since?.slice(0, 10) ?? "-"
|
|
20896
20997
|
])
|
|
20897
20998
|
];
|
|
20898
20999
|
console.log(table(rows));
|
|
@@ -20903,7 +21004,7 @@ function registerFriendsCommand(program2) {
|
|
|
20903
21004
|
process.exit(1);
|
|
20904
21005
|
}
|
|
20905
21006
|
});
|
|
20906
|
-
program2.command("
|
|
21007
|
+
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) => {
|
|
20907
21008
|
const auth = resolveAuth();
|
|
20908
21009
|
const spinner = opts.json ? null : ora("Sending friend request...").start();
|
|
20909
21010
|
try {
|
|
@@ -20923,7 +21024,7 @@ function registerFriendsCommand(program2) {
|
|
|
20923
21024
|
process.exit(1);
|
|
20924
21025
|
}
|
|
20925
21026
|
});
|
|
20926
|
-
program2.command("
|
|
21027
|
+
program2.command("accept <friendshipId>").description("Accept a pending friend request").option("--json", "Output as JSON").action(async (friendshipId, opts) => {
|
|
20927
21028
|
const auth = resolveAuth();
|
|
20928
21029
|
const spinner = opts.json ? null : ora("Accepting...").start();
|
|
20929
21030
|
try {
|
|
@@ -20936,11 +21037,11 @@ function registerFriendsCommand(program2) {
|
|
|
20936
21037
|
process.exit(1);
|
|
20937
21038
|
}
|
|
20938
21039
|
});
|
|
20939
|
-
program2.command("
|
|
21040
|
+
program2.command("remove <friendshipId>").description("Remove a friend").option("--yes", "Skip confirmation").option("--json", "Output as JSON").action(async (friendshipId, opts) => {
|
|
20940
21041
|
await confirmDestructive({
|
|
20941
21042
|
action: `Remove friend ${friendshipId}`,
|
|
20942
21043
|
yes: opts.yes,
|
|
20943
|
-
commandExample: `amiko friends
|
|
21044
|
+
commandExample: `amiko friends remove ${friendshipId}`
|
|
20944
21045
|
});
|
|
20945
21046
|
const auth = resolveAuth();
|
|
20946
21047
|
const spinner = opts.json ? null : ora("Removing...").start();
|
|
@@ -20999,7 +21100,9 @@ function registerFeedCommand(program2) {
|
|
|
20999
21100
|
process.exit(1);
|
|
21000
21101
|
}
|
|
21001
21102
|
});
|
|
21002
|
-
|
|
21103
|
+
}
|
|
21104
|
+
function registerPostCommand(program2) {
|
|
21105
|
+
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) => {
|
|
21003
21106
|
const auth = resolveAuth();
|
|
21004
21107
|
const visibility = opts.visibility === "private" ? "private" : "public";
|
|
21005
21108
|
const spinner = opts.json ? null : ora("Publishing post...").start();
|
|
@@ -21027,7 +21130,7 @@ function registerFeedCommand(program2) {
|
|
|
21027
21130
|
process.exit(1);
|
|
21028
21131
|
}
|
|
21029
21132
|
});
|
|
21030
|
-
program2.command("
|
|
21133
|
+
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) => {
|
|
21031
21134
|
const config2 = loadConfig();
|
|
21032
21135
|
const auth = resolveAuth();
|
|
21033
21136
|
let twinId;
|
|
@@ -21079,7 +21182,7 @@ function twinFromFlag3(opts) {
|
|
|
21079
21182
|
}
|
|
21080
21183
|
}
|
|
21081
21184
|
function registerComposioCommand(program2) {
|
|
21082
|
-
program2.command("
|
|
21185
|
+
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) => {
|
|
21083
21186
|
const { twinId, auth } = twinFromFlag3(opts);
|
|
21084
21187
|
const spinner = opts.json ? null : ora(`Connecting ${opts.app}...`).start();
|
|
21085
21188
|
try {
|
|
@@ -21115,13 +21218,13 @@ function registerComposioCommand(program2) {
|
|
|
21115
21218
|
process.exit(1);
|
|
21116
21219
|
}
|
|
21117
21220
|
});
|
|
21118
|
-
program2.command("
|
|
21221
|
+
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) => {
|
|
21119
21222
|
const { twinId, auth } = twinFromFlag3(opts);
|
|
21120
21223
|
await confirmDestructive({
|
|
21121
21224
|
action: `Disconnect ${opts.app}`,
|
|
21122
21225
|
detail: "The twin will lose access to the app's tools until reconnected.",
|
|
21123
21226
|
yes: opts.yes,
|
|
21124
|
-
commandExample: `amiko composio
|
|
21227
|
+
commandExample: `amiko composio disconnect --app ${opts.app}`
|
|
21125
21228
|
});
|
|
21126
21229
|
const spinner = opts.json ? null : ora("Finding connection...").start();
|
|
21127
21230
|
try {
|
|
@@ -21145,6 +21248,141 @@ function registerComposioCommand(program2) {
|
|
|
21145
21248
|
});
|
|
21146
21249
|
}
|
|
21147
21250
|
|
|
21251
|
+
// src/commands/wallets.ts
|
|
21252
|
+
function formatBalance(b) {
|
|
21253
|
+
const n = Number(b.amount) / 10 ** b.decimals;
|
|
21254
|
+
if (!isFinite(n))
|
|
21255
|
+
return b.amount;
|
|
21256
|
+
return n.toLocaleString(undefined, { maximumFractionDigits: 6 });
|
|
21257
|
+
}
|
|
21258
|
+
function registerWalletsBalanceCommand(program2) {
|
|
21259
|
+
program2.command("balance <address>").description("Sync and show balance for a single wallet").option("--json", "Output raw JSON").action(async (address2, opts) => {
|
|
21260
|
+
let auth;
|
|
21261
|
+
try {
|
|
21262
|
+
auth = requireAuth();
|
|
21263
|
+
} catch (e) {
|
|
21264
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21265
|
+
process.exit(1);
|
|
21266
|
+
}
|
|
21267
|
+
const spinner = opts.json ? null : ora("Syncing wallet balance...").start();
|
|
21268
|
+
try {
|
|
21269
|
+
const data = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(address2)}/balance`);
|
|
21270
|
+
spinner?.stop();
|
|
21271
|
+
if (opts.json) {
|
|
21272
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21273
|
+
return;
|
|
21274
|
+
}
|
|
21275
|
+
console.log(heading("Wallet Balance"));
|
|
21276
|
+
console.log("");
|
|
21277
|
+
console.log(label("Address", data.walletAddress));
|
|
21278
|
+
console.log(label("Chain", data.chain_type));
|
|
21279
|
+
if (data.last_synced_at) {
|
|
21280
|
+
console.log(label("Synced", data.last_synced_at));
|
|
21281
|
+
}
|
|
21282
|
+
const entries = Object.entries(data.balances || {});
|
|
21283
|
+
if (entries.length === 0) {
|
|
21284
|
+
console.log(dim(" No balances."));
|
|
21285
|
+
return;
|
|
21286
|
+
}
|
|
21287
|
+
console.log("");
|
|
21288
|
+
const rows = entries.map(([key, v]) => [` ${key}`, formatBalance(v)]);
|
|
21289
|
+
console.log(table(rows));
|
|
21290
|
+
} catch (e) {
|
|
21291
|
+
spinner?.stop();
|
|
21292
|
+
console.error(error(e instanceof Error ? e.message : "Failed to fetch balance"));
|
|
21293
|
+
process.exit(1);
|
|
21294
|
+
}
|
|
21295
|
+
});
|
|
21296
|
+
}
|
|
21297
|
+
function registerWalletsCreateCommand(program2) {
|
|
21298
|
+
program2.command("create").description("Create a new wallet for the twin on solana or base").requiredOption("--chain <chain>", "Chain to create the wallet on (solana | base)").option("--custodian <custodian>", "Custodian (crossmint | amiko). Defaults to crossmint; amiko is solana-only.", "crossmint").option("--json", "Output raw JSON").action(async (opts) => {
|
|
21299
|
+
const chain = opts.chain.toLowerCase();
|
|
21300
|
+
if (!["solana", "base"].includes(chain)) {
|
|
21301
|
+
console.error(error(`Unsupported chain '${opts.chain}'. Use solana or base.`));
|
|
21302
|
+
process.exit(1);
|
|
21303
|
+
}
|
|
21304
|
+
let auth;
|
|
21305
|
+
try {
|
|
21306
|
+
auth = requireAuth();
|
|
21307
|
+
} catch (e) {
|
|
21308
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21309
|
+
process.exit(1);
|
|
21310
|
+
}
|
|
21311
|
+
const spinner = opts.json ? null : ora(`Creating ${chain} wallet...`).start();
|
|
21312
|
+
try {
|
|
21313
|
+
const wallet = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets`, { method: "POST", body: { chain, custodian: opts.custodian } });
|
|
21314
|
+
spinner?.stop();
|
|
21315
|
+
if (opts.json) {
|
|
21316
|
+
console.log(JSON.stringify(wallet, null, 2));
|
|
21317
|
+
return;
|
|
21318
|
+
}
|
|
21319
|
+
console.log(success(`${chain} wallet created`));
|
|
21320
|
+
console.log("");
|
|
21321
|
+
console.log(label("Chain", `${wallet.chain} (${wallet.chain_type})`));
|
|
21322
|
+
if (wallet.name)
|
|
21323
|
+
console.log(label("Name", wallet.name));
|
|
21324
|
+
console.log(label("Address", wallet.wallet_address));
|
|
21325
|
+
console.log(label("Custodian", wallet.custodian ?? "-"));
|
|
21326
|
+
console.log("");
|
|
21327
|
+
console.log(dim(`Tip: paid commands (swap, markets search, image, amazon, services) will now use this wallet by default.`));
|
|
21328
|
+
} catch (e) {
|
|
21329
|
+
spinner?.stop();
|
|
21330
|
+
const msg = e instanceof Error ? e.message : "Failed to create wallet";
|
|
21331
|
+
if (/409|already/i.test(msg)) {
|
|
21332
|
+
console.error(error(`An active ${chain} wallet already exists. Run \`amiko wallets list\` to see it.`));
|
|
21333
|
+
} else {
|
|
21334
|
+
console.error(error(msg));
|
|
21335
|
+
}
|
|
21336
|
+
process.exit(1);
|
|
21337
|
+
}
|
|
21338
|
+
});
|
|
21339
|
+
}
|
|
21340
|
+
function registerWalletsListCommand(program2) {
|
|
21341
|
+
program2.command("list").alias("ls").description("List wallets for the authenticated twin").option("--json", "Output raw JSON").action(async (opts) => {
|
|
21342
|
+
let auth;
|
|
21343
|
+
try {
|
|
21344
|
+
auth = requireAuth();
|
|
21345
|
+
} catch (e) {
|
|
21346
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21347
|
+
process.exit(1);
|
|
21348
|
+
}
|
|
21349
|
+
const spinner = opts.json ? null : ora("Fetching wallets...").start();
|
|
21350
|
+
try {
|
|
21351
|
+
const data = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets`);
|
|
21352
|
+
spinner?.stop();
|
|
21353
|
+
if (opts.json) {
|
|
21354
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21355
|
+
return;
|
|
21356
|
+
}
|
|
21357
|
+
const wallets = data.wallets || [];
|
|
21358
|
+
if (wallets.length === 0) {
|
|
21359
|
+
console.log(dim("No wallets found."));
|
|
21360
|
+
return;
|
|
21361
|
+
}
|
|
21362
|
+
console.log(heading("Wallets"));
|
|
21363
|
+
console.log("");
|
|
21364
|
+
for (const w of wallets) {
|
|
21365
|
+
console.log(label("Chain", `${w.chain} (${w.chain_type})`));
|
|
21366
|
+
if (w.name)
|
|
21367
|
+
console.log(label("Name", w.name));
|
|
21368
|
+
console.log(label("Address", w.wallet_address));
|
|
21369
|
+
console.log(label("Short", truncAddr(w.wallet_address)));
|
|
21370
|
+
const balances = Object.entries(w.balance || {}).filter(([, v]) => Number(v.amount) > 0);
|
|
21371
|
+
if (balances.length > 0) {
|
|
21372
|
+
console.log(dim(" Balances:"));
|
|
21373
|
+
const rows = balances.map(([key, v]) => [` ${key}`, formatBalance(v)]);
|
|
21374
|
+
console.log(table(rows));
|
|
21375
|
+
}
|
|
21376
|
+
console.log("");
|
|
21377
|
+
}
|
|
21378
|
+
} catch (e) {
|
|
21379
|
+
spinner?.stop();
|
|
21380
|
+
console.error(error(e instanceof Error ? e.message : "Failed to list wallets"));
|
|
21381
|
+
process.exit(1);
|
|
21382
|
+
}
|
|
21383
|
+
});
|
|
21384
|
+
}
|
|
21385
|
+
|
|
21148
21386
|
// src/index.ts
|
|
21149
21387
|
var require2 = createRequire2(import.meta.url);
|
|
21150
21388
|
var { version: PKG_VERSION } = require2("../package.json");
|
|
@@ -21152,23 +21390,36 @@ var didOnboard = await runOnboarding(process.argv);
|
|
|
21152
21390
|
if (didOnboard)
|
|
21153
21391
|
process.exit(0);
|
|
21154
21392
|
var program2 = new Command;
|
|
21155
|
-
program2.name("amiko").description("Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call
|
|
21393
|
+
program2.name("amiko").description("Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call marketplace services").version(PKG_VERSION);
|
|
21394
|
+
var markets = program2.command("markets").description("MPP marketplace — discover and call paid AMIKO services");
|
|
21395
|
+
var wallets = program2.command("wallets").description("Manage twin wallets — list, swap, bridge");
|
|
21396
|
+
var twin = program2.command("twin").description("Update twin identity (name, description, visibility)");
|
|
21397
|
+
var docs = program2.command("docs").description("Manage twin RAG documents — list, upload, delete, presign");
|
|
21398
|
+
var voice = program2.command("voice").description("Manage twin voice — design, create, clone, reset");
|
|
21399
|
+
var avatar = program2.command("avatar").description("Manage twin avatar image");
|
|
21400
|
+
var friends = program2.command("friends").description("Manage friendships — list, add, accept, remove");
|
|
21401
|
+
var post = program2.command("post").description("Create posts and comments on the feed");
|
|
21402
|
+
var composio = program2.command("composio").description("Manage Composio app connections");
|
|
21156
21403
|
registerCreditsCommand(program2);
|
|
21157
|
-
registerSearchCommand(
|
|
21158
|
-
registerImageCommand(
|
|
21159
|
-
registerAmazonCommand(
|
|
21160
|
-
|
|
21161
|
-
|
|
21404
|
+
registerSearchCommand(markets);
|
|
21405
|
+
registerImageCommand(markets);
|
|
21406
|
+
registerAmazonCommand(markets);
|
|
21407
|
+
registerWalletsCreateCommand(wallets);
|
|
21408
|
+
registerWalletsListCommand(wallets);
|
|
21409
|
+
registerWalletsBalanceCommand(wallets);
|
|
21410
|
+
registerSwapCommand(wallets);
|
|
21411
|
+
registerBridgeCommand(wallets);
|
|
21162
21412
|
registerConfigCommand(program2);
|
|
21163
|
-
registerServicesCommand(
|
|
21164
|
-
registerDiscoveryCommand(
|
|
21413
|
+
registerServicesCommand(markets);
|
|
21414
|
+
registerDiscoveryCommand(markets);
|
|
21165
21415
|
registerUpdateCommand(program2);
|
|
21166
21416
|
registerAccountsCommand(program2);
|
|
21167
|
-
registerTwinCommand(
|
|
21168
|
-
registerDocsCommand(
|
|
21169
|
-
registerVoiceCommand(
|
|
21170
|
-
registerAvatarCommand(
|
|
21171
|
-
registerFriendsCommand(
|
|
21417
|
+
registerTwinCommand(twin);
|
|
21418
|
+
registerDocsCommand(docs);
|
|
21419
|
+
registerVoiceCommand(voice);
|
|
21420
|
+
registerAvatarCommand(avatar);
|
|
21421
|
+
registerFriendsCommand(friends);
|
|
21172
21422
|
registerFeedCommand(program2);
|
|
21173
|
-
|
|
21423
|
+
registerPostCommand(post);
|
|
21424
|
+
registerComposioCommand(composio);
|
|
21174
21425
|
program2.parse();
|