@heyamiko/amiko-cli 0.3.4 → 0.3.6
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 +37 -3
- package/dist/index.js +361 -127
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,6 +30,9 @@ amiko credits balance
|
|
|
30
30
|
# Top up credits from your agent's wallet
|
|
31
31
|
amiko credits topup 10000 --token AMIKO --yes
|
|
32
32
|
|
|
33
|
+
# Swap tokens on Solana
|
|
34
|
+
amiko swap send 1 amiko usdc
|
|
35
|
+
|
|
33
36
|
# Browse and call marketplace agents
|
|
34
37
|
amiko browse
|
|
35
38
|
amiko call titan-research "Summarize the latest AI news"
|
|
@@ -45,7 +48,7 @@ amiko connect amk_<key> # API key (shown once at creation)
|
|
|
45
48
|
amiko connect # browser sign-in flow
|
|
46
49
|
```
|
|
47
50
|
|
|
48
|
-
The connect code is the simplest — generate one from your Amiko settings page, paste it to the agent or terminal.
|
|
51
|
+
The connect code is the simplest — generate one from your Amiko settings page, paste it to the agent or terminal. Connect auto-detects your Solana wallet for swaps.
|
|
49
52
|
|
|
50
53
|
```bash
|
|
51
54
|
amiko whoami # show current auth status
|
|
@@ -122,13 +125,41 @@ amiko creator publish <id> # publish a draft
|
|
|
122
125
|
amiko creator payout # request payout
|
|
123
126
|
```
|
|
124
127
|
|
|
128
|
+
## Swap (Solana)
|
|
129
|
+
|
|
130
|
+
Swap tokens on Solana via Jupiter aggregator. Wallet auto-detected from your connected account — no setup needed.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
amiko swap send 1 amiko usdc # swap 1 AMIKO → USDC (auto-detect wallet)
|
|
134
|
+
amiko swap send 5 usdt usdc --yes # skip confirmation
|
|
135
|
+
amiko swap send 0.1 sol usdc # SOL → USDC
|
|
136
|
+
amiko swap quote 1 amiko usdc # preview without executing
|
|
137
|
+
amiko swap tokens # list supported tokens
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Supports symbols (`sol`, `usdc`, `usdt`, `amiko`, `bonk`, `jup`, `pyusd`, `jitosol`, `ray`, `wbtc`) or raw mint addresses.
|
|
141
|
+
|
|
142
|
+
Swaps execute via Crossmint smart wallets — your agent wallet signs and submits on-chain automatically.
|
|
143
|
+
|
|
144
|
+
## Bridge (Cross-Chain)
|
|
145
|
+
|
|
146
|
+
Bridge tokens across 26+ chains via Across Protocol:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
amiko bridge quote 10 # Solana → Tempo (default)
|
|
150
|
+
amiko bridge quote 5 --from base --to tempo
|
|
151
|
+
amiko bridge send 10 --from solana --to tempo --recipient 0x...
|
|
152
|
+
amiko bridge routes # list available routes
|
|
153
|
+
amiko bridge limits # check transfer limits
|
|
154
|
+
amiko bridge status <txHash> # track bridge status
|
|
155
|
+
```
|
|
156
|
+
|
|
125
157
|
## Other Commands
|
|
126
158
|
|
|
127
159
|
```bash
|
|
128
160
|
amiko reputation [address] # TARS score
|
|
129
161
|
amiko discover # MPP service info
|
|
130
162
|
amiko ping # health check
|
|
131
|
-
amiko bridge quote 5 # cross-chain bridge quote
|
|
132
163
|
amiko config show # view config
|
|
133
164
|
amiko config set <key> <value> # set config value
|
|
134
165
|
amiko update # update CLI to latest
|
|
@@ -143,9 +174,10 @@ npm install -g @heyamiko/amiko-cli
|
|
|
143
174
|
amiko connect <CODE>
|
|
144
175
|
amiko credits balance
|
|
145
176
|
amiko credits topup 10000 --token AMIKO --yes
|
|
177
|
+
amiko swap send 1 amiko usdc # swap tokens on Solana
|
|
146
178
|
```
|
|
147
179
|
|
|
148
|
-
The CLI auto-detects `.amiko.json` (synced by the platform) when running on an agent.
|
|
180
|
+
Connect auto-detects the agent's Solana wallet — no manual wallet setup needed. The CLI auto-detects `.amiko.json` (synced by the platform) when running on an agent.
|
|
149
181
|
|
|
150
182
|
## Configuration
|
|
151
183
|
|
|
@@ -166,6 +198,8 @@ src/
|
|
|
166
198
|
├── commands/
|
|
167
199
|
│ ├── connect.ts # connect (code, API key, browser)
|
|
168
200
|
│ ├── credits.ts # credits balance + topup
|
|
201
|
+
│ ├── swap.ts # Solana token swaps (Jupiter)
|
|
202
|
+
│ ├── bridge.ts # cross-chain bridging (Across)
|
|
169
203
|
│ ├── browse.ts # marketplace browsing
|
|
170
204
|
│ ├── call.ts # call agents
|
|
171
205
|
│ ├── wallet.ts # MPP wallet management
|
package/dist/index.js
CHANGED
|
@@ -1886,6 +1886,76 @@ var require_commander = __commonJS((exports) => {
|
|
|
1886
1886
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
1887
1887
|
});
|
|
1888
1888
|
|
|
1889
|
+
// src/lib/config.ts
|
|
1890
|
+
var exports_config = {};
|
|
1891
|
+
__export(exports_config, {
|
|
1892
|
+
saveConfig: () => saveConfig,
|
|
1893
|
+
resetConfig: () => resetConfig,
|
|
1894
|
+
loadConfig: () => loadConfig,
|
|
1895
|
+
getPrivyToken: () => getPrivyToken,
|
|
1896
|
+
getConfigPath: () => getConfigPath
|
|
1897
|
+
});
|
|
1898
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
1899
|
+
import { homedir } from "node:os";
|
|
1900
|
+
import { join } from "node:path";
|
|
1901
|
+
function loadConfig() {
|
|
1902
|
+
if (!existsSync(CONFIG_FILE))
|
|
1903
|
+
return { ...DEFAULTS };
|
|
1904
|
+
try {
|
|
1905
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
1906
|
+
const parsed = JSON.parse(raw);
|
|
1907
|
+
return normalizeConfig({ ...DEFAULTS, ...parsed });
|
|
1908
|
+
} catch {
|
|
1909
|
+
return { ...DEFAULTS };
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
function saveConfig(config) {
|
|
1913
|
+
const current = loadConfig();
|
|
1914
|
+
const merged = normalizeConfig({ ...current, ...config });
|
|
1915
|
+
if (!existsSync(CONFIG_DIR))
|
|
1916
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1917
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + `
|
|
1918
|
+
`);
|
|
1919
|
+
return merged;
|
|
1920
|
+
}
|
|
1921
|
+
function getConfigPath() {
|
|
1922
|
+
return CONFIG_FILE;
|
|
1923
|
+
}
|
|
1924
|
+
function resetConfig() {
|
|
1925
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
1926
|
+
return false;
|
|
1927
|
+
}
|
|
1928
|
+
unlinkSync(CONFIG_FILE);
|
|
1929
|
+
return true;
|
|
1930
|
+
}
|
|
1931
|
+
function getPrivyToken(config) {
|
|
1932
|
+
return config.privyToken || config.creatorToken;
|
|
1933
|
+
}
|
|
1934
|
+
function normalizeConfig(config) {
|
|
1935
|
+
const normalized = { ...config };
|
|
1936
|
+
if (!normalized.privyToken && normalized.creatorToken) {
|
|
1937
|
+
normalized.privyToken = normalized.creatorToken;
|
|
1938
|
+
}
|
|
1939
|
+
if (LEGACY_SITE_BASES.has(normalized.siteBase)) {
|
|
1940
|
+
normalized.siteBase = DEFAULTS.siteBase;
|
|
1941
|
+
}
|
|
1942
|
+
return normalized;
|
|
1943
|
+
}
|
|
1944
|
+
var CONFIG_DIR, CONFIG_FILE, DEFAULTS, LEGACY_SITE_BASES;
|
|
1945
|
+
var init_config = __esm(() => {
|
|
1946
|
+
CONFIG_DIR = join(homedir(), ".amiko");
|
|
1947
|
+
CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
1948
|
+
DEFAULTS = {
|
|
1949
|
+
apiBase: "https://mpp.amikomarkets.com",
|
|
1950
|
+
billingBase: "https://billing.heyamiko.com",
|
|
1951
|
+
siteBase: "https://platform.heyamiko.com"
|
|
1952
|
+
};
|
|
1953
|
+
LEGACY_SITE_BASES = new Set([
|
|
1954
|
+
"https://amiko-markets.vercel.app",
|
|
1955
|
+
"https://amiko-markets.vercel.app/"
|
|
1956
|
+
]);
|
|
1957
|
+
});
|
|
1958
|
+
|
|
1889
1959
|
// node_modules/cli-spinners/spinners.json
|
|
1890
1960
|
var require_spinners = __commonJS((exports, module) => {
|
|
1891
1961
|
module.exports = {
|
|
@@ -3533,6 +3603,80 @@ var require_emoji_regex = __commonJS((exports, module) => {
|
|
|
3533
3603
|
};
|
|
3534
3604
|
});
|
|
3535
3605
|
|
|
3606
|
+
// src/lib/agent-config.ts
|
|
3607
|
+
var exports_agent_config = {};
|
|
3608
|
+
__export(exports_agent_config, {
|
|
3609
|
+
resolveAuth: () => resolveAuth,
|
|
3610
|
+
loadAgentConfig: () => loadAgentConfig
|
|
3611
|
+
});
|
|
3612
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
3613
|
+
import { join as join3, resolve } from "node:path";
|
|
3614
|
+
function loadAgentConfig() {
|
|
3615
|
+
let dir = process.cwd();
|
|
3616
|
+
const root = resolve("/");
|
|
3617
|
+
while (dir !== root) {
|
|
3618
|
+
const filePath = join3(dir, ".amiko.json");
|
|
3619
|
+
if (existsSync3(filePath)) {
|
|
3620
|
+
try {
|
|
3621
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
3622
|
+
const parsed = JSON.parse(raw);
|
|
3623
|
+
const config = {};
|
|
3624
|
+
if (parsed.amikoTwinToken)
|
|
3625
|
+
config.twinToken = parsed.amikoTwinToken;
|
|
3626
|
+
if (parsed.amikoTwinId)
|
|
3627
|
+
config.twinId = parsed.amikoTwinId;
|
|
3628
|
+
if (parsed.amikoUserId)
|
|
3629
|
+
config.userId = parsed.amikoUserId;
|
|
3630
|
+
if (parsed.amikoPlatformUrl)
|
|
3631
|
+
config.platformUrl = parsed.amikoPlatformUrl;
|
|
3632
|
+
return Object.keys(config).length > 0 ? config : null;
|
|
3633
|
+
} catch {
|
|
3634
|
+
return null;
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
dir = resolve(dir, "..");
|
|
3638
|
+
}
|
|
3639
|
+
return null;
|
|
3640
|
+
}
|
|
3641
|
+
function resolveAuth(cliConfig) {
|
|
3642
|
+
if (cliConfig.agentWallets?.length) {
|
|
3643
|
+
return {
|
|
3644
|
+
mode: "connected",
|
|
3645
|
+
platformUrl: cliConfig.platformUrl,
|
|
3646
|
+
billingBase: cliConfig.billingBase,
|
|
3647
|
+
twinId: cliConfig.twinId,
|
|
3648
|
+
twinToken: cliConfig.twinToken,
|
|
3649
|
+
platformKey: cliConfig.apiKey,
|
|
3650
|
+
privyToken: cliConfig.privyToken,
|
|
3651
|
+
connectedKeyId: cliConfig.connectedKeyId,
|
|
3652
|
+
userId: cliConfig.userId,
|
|
3653
|
+
agentWallets: cliConfig.agentWallets
|
|
3654
|
+
};
|
|
3655
|
+
}
|
|
3656
|
+
if (cliConfig.privyToken && cliConfig.connectedKeyId) {
|
|
3657
|
+
return {
|
|
3658
|
+
mode: "connected",
|
|
3659
|
+
billingBase: cliConfig.billingBase,
|
|
3660
|
+
platformKey: cliConfig.privyToken,
|
|
3661
|
+
privyToken: cliConfig.privyToken,
|
|
3662
|
+
connectedKeyId: cliConfig.connectedKeyId,
|
|
3663
|
+
userId: cliConfig.userId
|
|
3664
|
+
};
|
|
3665
|
+
}
|
|
3666
|
+
const agentConfig = loadAgentConfig();
|
|
3667
|
+
if (agentConfig?.twinToken) {
|
|
3668
|
+
return {
|
|
3669
|
+
mode: "agent",
|
|
3670
|
+
platformUrl: agentConfig.platformUrl,
|
|
3671
|
+
twinId: agentConfig.twinId,
|
|
3672
|
+
twinToken: agentConfig.twinToken,
|
|
3673
|
+
userId: agentConfig.userId
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3676
|
+
return { mode: "none" };
|
|
3677
|
+
}
|
|
3678
|
+
var init_agent_config = () => {};
|
|
3679
|
+
|
|
3536
3680
|
// node_modules/@solana/errors/dist/index.node.mjs
|
|
3537
3681
|
function getHumanReadableErrorMessage(code, context = {}) {
|
|
3538
3682
|
const messageFormatString = SolanaErrorMessages[code];
|
|
@@ -23300,67 +23444,9 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
23300
23444
|
var source_default = chalk;
|
|
23301
23445
|
|
|
23302
23446
|
// src/onboarding.ts
|
|
23447
|
+
init_config();
|
|
23303
23448
|
import { createInterface } from "node:readline";
|
|
23304
23449
|
|
|
23305
|
-
// src/lib/config.ts
|
|
23306
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
23307
|
-
import { homedir } from "node:os";
|
|
23308
|
-
import { join } from "node:path";
|
|
23309
|
-
var CONFIG_DIR = join(homedir(), ".amiko");
|
|
23310
|
-
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
23311
|
-
var DEFAULTS = {
|
|
23312
|
-
apiBase: "https://mpp.amikomarkets.com",
|
|
23313
|
-
billingBase: "https://billing.heyamiko.com",
|
|
23314
|
-
siteBase: "https://platform.heyamiko.com"
|
|
23315
|
-
};
|
|
23316
|
-
var LEGACY_SITE_BASES = new Set([
|
|
23317
|
-
"https://amiko-markets.vercel.app",
|
|
23318
|
-
"https://amiko-markets.vercel.app/"
|
|
23319
|
-
]);
|
|
23320
|
-
function loadConfig() {
|
|
23321
|
-
if (!existsSync(CONFIG_FILE))
|
|
23322
|
-
return { ...DEFAULTS };
|
|
23323
|
-
try {
|
|
23324
|
-
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
23325
|
-
const parsed = JSON.parse(raw);
|
|
23326
|
-
return normalizeConfig({ ...DEFAULTS, ...parsed });
|
|
23327
|
-
} catch {
|
|
23328
|
-
return { ...DEFAULTS };
|
|
23329
|
-
}
|
|
23330
|
-
}
|
|
23331
|
-
function saveConfig(config) {
|
|
23332
|
-
const current = loadConfig();
|
|
23333
|
-
const merged = normalizeConfig({ ...current, ...config });
|
|
23334
|
-
if (!existsSync(CONFIG_DIR))
|
|
23335
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
23336
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + `
|
|
23337
|
-
`);
|
|
23338
|
-
return merged;
|
|
23339
|
-
}
|
|
23340
|
-
function getConfigPath() {
|
|
23341
|
-
return CONFIG_FILE;
|
|
23342
|
-
}
|
|
23343
|
-
function resetConfig() {
|
|
23344
|
-
if (!existsSync(CONFIG_FILE)) {
|
|
23345
|
-
return false;
|
|
23346
|
-
}
|
|
23347
|
-
unlinkSync(CONFIG_FILE);
|
|
23348
|
-
return true;
|
|
23349
|
-
}
|
|
23350
|
-
function getPrivyToken(config) {
|
|
23351
|
-
return config.privyToken || config.creatorToken;
|
|
23352
|
-
}
|
|
23353
|
-
function normalizeConfig(config) {
|
|
23354
|
-
const normalized = { ...config };
|
|
23355
|
-
if (!normalized.privyToken && normalized.creatorToken) {
|
|
23356
|
-
normalized.privyToken = normalized.creatorToken;
|
|
23357
|
-
}
|
|
23358
|
-
if (LEGACY_SITE_BASES.has(normalized.siteBase)) {
|
|
23359
|
-
normalized.siteBase = DEFAULTS.siteBase;
|
|
23360
|
-
}
|
|
23361
|
-
return normalized;
|
|
23362
|
-
}
|
|
23363
|
-
|
|
23364
23450
|
// src/lib/format.ts
|
|
23365
23451
|
function table(rows) {
|
|
23366
23452
|
if (rows.length === 0)
|
|
@@ -24372,6 +24458,7 @@ function ora(options) {
|
|
|
24372
24458
|
}
|
|
24373
24459
|
|
|
24374
24460
|
// src/lib/api.ts
|
|
24461
|
+
init_config();
|
|
24375
24462
|
function mppBase() {
|
|
24376
24463
|
return trimBase(loadConfig().apiBase);
|
|
24377
24464
|
}
|
|
@@ -24480,6 +24567,7 @@ function trimBase(base) {
|
|
|
24480
24567
|
}
|
|
24481
24568
|
|
|
24482
24569
|
// src/commands/browse.ts
|
|
24570
|
+
init_config();
|
|
24483
24571
|
function siteUrl(agentSlug) {
|
|
24484
24572
|
const config = loadConfig();
|
|
24485
24573
|
return `${config.siteBase}/agents/${agentSlug}`;
|
|
@@ -24615,6 +24703,7 @@ function registerBrowseCommand(program2) {
|
|
|
24615
24703
|
}
|
|
24616
24704
|
|
|
24617
24705
|
// src/commands/call.ts
|
|
24706
|
+
init_config();
|
|
24618
24707
|
import { createInterface as createInterface2 } from "node:readline";
|
|
24619
24708
|
|
|
24620
24709
|
// src/lib/tempo.ts
|
|
@@ -24950,6 +25039,7 @@ function registerCallCommand(program2) {
|
|
|
24950
25039
|
}
|
|
24951
25040
|
|
|
24952
25041
|
// src/commands/wallet.ts
|
|
25042
|
+
init_config();
|
|
24953
25043
|
function sanitizeTempoWhoamiOutput(output) {
|
|
24954
25044
|
return output.replace(/^(\s*key:\s*)"[^"\n]*"$/m, '$1"[redacted]"');
|
|
24955
25045
|
}
|
|
@@ -25148,6 +25238,7 @@ Tip: add --open to auto-launch in browser.`));
|
|
|
25148
25238
|
}
|
|
25149
25239
|
|
|
25150
25240
|
// src/commands/creator.ts
|
|
25241
|
+
init_config();
|
|
25151
25242
|
function requireCreatorToken() {
|
|
25152
25243
|
const config = loadConfig();
|
|
25153
25244
|
const token = getPrivyToken(config);
|
|
@@ -25277,6 +25368,7 @@ function registerCreatorCommand(program2) {
|
|
|
25277
25368
|
}
|
|
25278
25369
|
|
|
25279
25370
|
// src/commands/reputation.ts
|
|
25371
|
+
init_config();
|
|
25280
25372
|
function registerReputationCommand(program2) {
|
|
25281
25373
|
program2.command("reputation").alias("rep").description("Look up TARS reputation for a wallet address").argument("[address]", "Wallet address (uses configured wallet if omitted)").action(async (address) => {
|
|
25282
25374
|
const addr = address || loadConfig().wallet;
|
|
@@ -25333,6 +25425,7 @@ function scoreTier(score) {
|
|
|
25333
25425
|
}
|
|
25334
25426
|
|
|
25335
25427
|
// src/commands/config.ts
|
|
25428
|
+
init_config();
|
|
25336
25429
|
var VALID_KEYS = [
|
|
25337
25430
|
"apiBase",
|
|
25338
25431
|
"billingBase",
|
|
@@ -25402,6 +25495,7 @@ function maskKey(key) {
|
|
|
25402
25495
|
}
|
|
25403
25496
|
|
|
25404
25497
|
// src/commands/discovery.ts
|
|
25498
|
+
init_config();
|
|
25405
25499
|
function registerDiscoveryCommand(program2) {
|
|
25406
25500
|
program2.command("discover").alias("status").description("Show MPP service info, endpoints, and pricing").action(async () => {
|
|
25407
25501
|
const config = loadConfig();
|
|
@@ -25489,6 +25583,7 @@ function registerDiscoveryCommand(program2) {
|
|
|
25489
25583
|
}
|
|
25490
25584
|
|
|
25491
25585
|
// src/commands/marketplace.ts
|
|
25586
|
+
init_config();
|
|
25492
25587
|
function timeAgo(timestamp) {
|
|
25493
25588
|
const seconds = Math.floor((Date.now() - new Date(timestamp).getTime()) / 1000);
|
|
25494
25589
|
if (seconds < 60)
|
|
@@ -25620,6 +25715,7 @@ function registerMarketplaceCommand(program2) {
|
|
|
25620
25715
|
}
|
|
25621
25716
|
|
|
25622
25717
|
// src/commands/login.ts
|
|
25718
|
+
init_config();
|
|
25623
25719
|
import { createServer } from "node:http";
|
|
25624
25720
|
import { randomBytes } from "node:crypto";
|
|
25625
25721
|
import { execSync } from "node:child_process";
|
|
@@ -25886,6 +25982,7 @@ function startCallbackServer(expectedState, timeoutMs = 120000, acknowledgementT
|
|
|
25886
25982
|
}
|
|
25887
25983
|
|
|
25888
25984
|
// src/lib/across.ts
|
|
25985
|
+
init_config();
|
|
25889
25986
|
function getBridgeBase() {
|
|
25890
25987
|
const config = loadConfig();
|
|
25891
25988
|
return `${config.apiBase}/v1/bridge`;
|
|
@@ -26035,6 +26132,7 @@ function getUsdcAddress(chainId) {
|
|
|
26035
26132
|
}
|
|
26036
26133
|
|
|
26037
26134
|
// src/commands/bridge.ts
|
|
26135
|
+
init_config();
|
|
26038
26136
|
var DEFAULT_ORIGIN = CHAINS.solana;
|
|
26039
26137
|
var DEFAULT_DESTINATION = CHAINS.tempo;
|
|
26040
26138
|
function registerBridgeCommand(program2) {
|
|
@@ -26367,9 +26465,200 @@ function registerBridgeCommand(program2) {
|
|
|
26367
26465
|
});
|
|
26368
26466
|
}
|
|
26369
26467
|
|
|
26468
|
+
// src/commands/swap.ts
|
|
26469
|
+
var KNOWN_TOKENS = {
|
|
26470
|
+
sol: { mint: "So11111111111111111111111111111111111111112", decimals: 9, name: "SOL" },
|
|
26471
|
+
wsol: { mint: "So11111111111111111111111111111111111111112", decimals: 9, name: "Wrapped SOL" },
|
|
26472
|
+
usdc: { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", decimals: 6, name: "USDC" },
|
|
26473
|
+
usdt: { mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", decimals: 6, name: "USDT" },
|
|
26474
|
+
pyusd: { mint: "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", decimals: 6, name: "PYUSD" },
|
|
26475
|
+
bonk: { mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", decimals: 5, name: "BONK" },
|
|
26476
|
+
jup: { mint: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", decimals: 6, name: "JUP" },
|
|
26477
|
+
jitosol: { mint: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn", decimals: 9, name: "JitoSOL" },
|
|
26478
|
+
ray: { mint: "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", decimals: 6, name: "RAY" },
|
|
26479
|
+
amiko: { mint: "AY1Ww6MxwC3cCiyrandHqLrp4FXvzgcwQTZpJ2FEpump", decimals: 6, name: "AMIKO" }
|
|
26480
|
+
};
|
|
26481
|
+
function resolveToken(input) {
|
|
26482
|
+
const lower = input.toLowerCase();
|
|
26483
|
+
const known = KNOWN_TOKENS[lower];
|
|
26484
|
+
if (known)
|
|
26485
|
+
return { mint: known.mint, decimals: known.decimals, symbol: known.name };
|
|
26486
|
+
return { mint: input, decimals: 6, symbol: truncAddr(input) };
|
|
26487
|
+
}
|
|
26488
|
+
function formatAmount(raw, decimals) {
|
|
26489
|
+
const n = typeof raw === "string" ? parseInt(raw, 10) : raw;
|
|
26490
|
+
return (n / 10 ** decimals).toFixed(decimals > 6 ? 4 : decimals);
|
|
26491
|
+
}
|
|
26492
|
+
function parseAmount(amount, decimals) {
|
|
26493
|
+
const num = parseFloat(amount);
|
|
26494
|
+
if (isNaN(num) || num <= 0)
|
|
26495
|
+
throw new Error(`Invalid amount: ${amount}`);
|
|
26496
|
+
return Math.round(num * 10 ** decimals).toString();
|
|
26497
|
+
}
|
|
26498
|
+
function registerSwapCommand(program2) {
|
|
26499
|
+
const cmd = program2.command("swap").description("Swap tokens on Solana via Jupiter");
|
|
26500
|
+
cmd.command("quote").description("Get a swap quote for Solana tokens").argument("<amount>", "Amount to swap (e.g., 5, 0.1)").argument("<from>", "Input token (sol, usdc, usdt, bonk, or mint address)").argument("<to>", "Output token (sol, usdc, usdt, bonk, or mint address)").option("--slippage <bps>", "Slippage tolerance in basis points", "50").action(async (amountStr, fromToken, toToken, opts) => {
|
|
26501
|
+
const spinner = ora("Fetching swap quote...").start();
|
|
26502
|
+
try {
|
|
26503
|
+
const input = resolveToken(fromToken);
|
|
26504
|
+
const output = resolveToken(toToken);
|
|
26505
|
+
const amount = parseAmount(amountStr, input.decimals);
|
|
26506
|
+
const params = new URLSearchParams({
|
|
26507
|
+
inputMint: input.mint,
|
|
26508
|
+
outputMint: output.mint,
|
|
26509
|
+
amount,
|
|
26510
|
+
slippageBps: opts.slippage
|
|
26511
|
+
});
|
|
26512
|
+
const quote = await get(`/v1/swap/quote?${params}`);
|
|
26513
|
+
spinner.stop();
|
|
26514
|
+
console.log(heading("Swap Quote"));
|
|
26515
|
+
console.log("");
|
|
26516
|
+
console.log(label("Input", `${formatAmount(quote.inAmount, input.decimals)} ${input.symbol}`));
|
|
26517
|
+
console.log(label("Output", `${formatAmount(quote.outAmount, output.decimals)} ${output.symbol}`));
|
|
26518
|
+
console.log(label("Min Output", `${formatAmount(quote.otherAmountThreshold, output.decimals)} ${output.symbol}`));
|
|
26519
|
+
if (quote.platformFee && parseInt(quote.platformFee.amount) > 0) {
|
|
26520
|
+
console.log(label("Platform Fee", `${formatAmount(quote.platformFee.amount, output.decimals)} ${output.symbol} (${quote.platformFee.feeBps} bps)`));
|
|
26521
|
+
}
|
|
26522
|
+
const impact = parseFloat(quote.priceImpactPct);
|
|
26523
|
+
if (impact > 0.1) {
|
|
26524
|
+
console.log(label("Price Impact", source_default.yellow(`${impact.toFixed(2)}%`)));
|
|
26525
|
+
} else {
|
|
26526
|
+
console.log(label("Price Impact", `${impact.toFixed(4)}%`));
|
|
26527
|
+
}
|
|
26528
|
+
console.log(label("Slippage", `${quote.slippageBps} bps`));
|
|
26529
|
+
if (quote.routePlan.length > 0) {
|
|
26530
|
+
const route = quote.routePlan.map((r) => r.swapInfo.label).join(" → ");
|
|
26531
|
+
console.log(label("Route", dim(route)));
|
|
26532
|
+
}
|
|
26533
|
+
console.log("");
|
|
26534
|
+
console.log(dim(`To execute: amiko swap send ${amountStr} ${fromToken} ${toToken}`));
|
|
26535
|
+
} catch (err) {
|
|
26536
|
+
spinner.stop();
|
|
26537
|
+
console.error(error(err instanceof Error ? err.message : "Failed to get quote"));
|
|
26538
|
+
process.exit(1);
|
|
26539
|
+
}
|
|
26540
|
+
});
|
|
26541
|
+
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>", "Wallet address (uses config wallet by default)").option("--slippage <bps>", "Slippage tolerance in basis points", "50").option("--yes", "Skip confirmation").action(async (amountStr, fromToken, toToken, opts) => {
|
|
26542
|
+
try {
|
|
26543
|
+
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
26544
|
+
const { resolveAuth: resolveAuth2 } = await Promise.resolve().then(() => (init_agent_config(), exports_agent_config));
|
|
26545
|
+
const config = loadConfig2();
|
|
26546
|
+
const auth = resolveAuth2(config);
|
|
26547
|
+
const solanaAgentWallet = config.agentWallets?.find((w) => w.chain === "solana" && w.source === "agent")?.address;
|
|
26548
|
+
const wallet = opts.wallet || config.wallet || solanaAgentWallet;
|
|
26549
|
+
if (!wallet) {
|
|
26550
|
+
console.error(error("No Solana wallet found. Provide --wallet or run: amiko connect"));
|
|
26551
|
+
process.exit(1);
|
|
26552
|
+
}
|
|
26553
|
+
if (auth.mode === "none") {
|
|
26554
|
+
console.error(error("Not connected. Run: amiko connect"));
|
|
26555
|
+
process.exit(1);
|
|
26556
|
+
}
|
|
26557
|
+
const input = resolveToken(fromToken);
|
|
26558
|
+
const output = resolveToken(toToken);
|
|
26559
|
+
const amount = parseAmount(amountStr, input.decimals);
|
|
26560
|
+
const quoteSpinner = ora("Fetching swap quote...").start();
|
|
26561
|
+
const quoteParams = new URLSearchParams({
|
|
26562
|
+
inputMint: input.mint,
|
|
26563
|
+
outputMint: output.mint,
|
|
26564
|
+
amount,
|
|
26565
|
+
slippageBps: opts.slippage
|
|
26566
|
+
});
|
|
26567
|
+
const quote = await get(`/v1/swap/quote?${quoteParams}`);
|
|
26568
|
+
quoteSpinner.stop();
|
|
26569
|
+
console.log(heading("Swap"));
|
|
26570
|
+
console.log("");
|
|
26571
|
+
console.log(label("Send", `${formatAmount(quote.inAmount, input.decimals)} ${input.symbol}`));
|
|
26572
|
+
console.log(label("Receive", `~${formatAmount(quote.outAmount, output.decimals)} ${output.symbol}`));
|
|
26573
|
+
if (quote.platformFee && parseInt(quote.platformFee.amount) > 0) {
|
|
26574
|
+
console.log(label("Fee", `${formatAmount(quote.platformFee.amount, output.decimals)} ${output.symbol} (${quote.platformFee.feeBps} bps)`));
|
|
26575
|
+
}
|
|
26576
|
+
const route = quote.routePlan.map((r) => r.swapInfo.label).join(" → ");
|
|
26577
|
+
if (route)
|
|
26578
|
+
console.log(label("Route", dim(route)));
|
|
26579
|
+
console.log(label("Wallet", truncAddr(wallet)));
|
|
26580
|
+
console.log("");
|
|
26581
|
+
if (!opts.yes) {
|
|
26582
|
+
const readline = await import("readline");
|
|
26583
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
26584
|
+
const answer = await new Promise((resolve2) => rl.question("Confirm swap? (y/N) ", resolve2));
|
|
26585
|
+
rl.close();
|
|
26586
|
+
if (answer.toLowerCase() !== "y") {
|
|
26587
|
+
console.log(dim("Cancelled."));
|
|
26588
|
+
process.exit(0);
|
|
26589
|
+
}
|
|
26590
|
+
}
|
|
26591
|
+
const swapSpinner = ora("Executing swap via Crossmint...").start();
|
|
26592
|
+
const billingToken = auth.platformKey || auth.privyToken;
|
|
26593
|
+
const billingBase2 = auth.billingBase;
|
|
26594
|
+
if (!billingBase2 || !billingToken) {
|
|
26595
|
+
swapSpinner.stop();
|
|
26596
|
+
console.error(error("No billing credentials. Run: amiko connect"));
|
|
26597
|
+
process.exit(1);
|
|
26598
|
+
}
|
|
26599
|
+
const swapRes = await fetch(`${billingBase2}/api/crossmint/wallets/${encodeURIComponent(wallet)}/swap`, {
|
|
26600
|
+
method: "POST",
|
|
26601
|
+
headers: {
|
|
26602
|
+
"Content-Type": "application/json",
|
|
26603
|
+
Authorization: `Bearer ${billingToken}`
|
|
26604
|
+
},
|
|
26605
|
+
body: JSON.stringify({
|
|
26606
|
+
inputMint: input.mint,
|
|
26607
|
+
outputMint: output.mint,
|
|
26608
|
+
amount,
|
|
26609
|
+
slippageBps: parseInt(opts.slippage)
|
|
26610
|
+
})
|
|
26611
|
+
});
|
|
26612
|
+
if (!swapRes.ok) {
|
|
26613
|
+
swapSpinner.stop();
|
|
26614
|
+
const err = await swapRes.json().catch(() => ({ error: "Swap failed" }));
|
|
26615
|
+
console.error(error(err.error || `Swap failed: ${swapRes.status}`));
|
|
26616
|
+
if (err.details)
|
|
26617
|
+
console.error(dim(typeof err.details === "string" ? err.details : JSON.stringify(err.details)));
|
|
26618
|
+
process.exit(1);
|
|
26619
|
+
}
|
|
26620
|
+
const swapData = await swapRes.json();
|
|
26621
|
+
swapSpinner.stop();
|
|
26622
|
+
console.log(success("Swap executed"));
|
|
26623
|
+
console.log("");
|
|
26624
|
+
if (swapData.txHash) {
|
|
26625
|
+
console.log(label("Tx Hash", dim(swapData.txHash)));
|
|
26626
|
+
console.log(label("Explorer", dim(swapData.explorerLink || `https://solscan.io/tx/${swapData.txHash}`)));
|
|
26627
|
+
}
|
|
26628
|
+
if (swapData.quote) {
|
|
26629
|
+
console.log(label("Input", `${formatAmount(swapData.quote.inAmount, input.decimals)} ${input.symbol}`));
|
|
26630
|
+
console.log(label("Output", `${formatAmount(swapData.quote.outAmount, output.decimals)} ${output.symbol}`));
|
|
26631
|
+
}
|
|
26632
|
+
} catch (err) {
|
|
26633
|
+
console.error(error(err instanceof Error ? err.message : "Swap failed"));
|
|
26634
|
+
process.exit(1);
|
|
26635
|
+
}
|
|
26636
|
+
});
|
|
26637
|
+
cmd.command("tokens").description("List supported Solana tokens for swapping").action(async () => {
|
|
26638
|
+
const spinner = ora("Fetching tokens...").start();
|
|
26639
|
+
try {
|
|
26640
|
+
const data = await get("/v1/swap/tokens");
|
|
26641
|
+
spinner.stop();
|
|
26642
|
+
console.log(heading("Solana Tokens"));
|
|
26643
|
+
console.log(dim(`${data.tokens.length} tokens (source: ${data.provider})
|
|
26644
|
+
`));
|
|
26645
|
+
for (const t of data.tokens) {
|
|
26646
|
+
console.log(` ${source_default.cyan(t.symbol.padEnd(10))} ${t.name.padEnd(25)} ${dim(truncAddr(t.address))}`);
|
|
26647
|
+
}
|
|
26648
|
+
console.log("");
|
|
26649
|
+
console.log(dim("Use symbol or mint address: amiko swap quote 5 usdt usdc"));
|
|
26650
|
+
} catch (err) {
|
|
26651
|
+
spinner.stop();
|
|
26652
|
+
console.error(error(err instanceof Error ? err.message : "Failed to fetch tokens"));
|
|
26653
|
+
process.exit(1);
|
|
26654
|
+
}
|
|
26655
|
+
});
|
|
26656
|
+
}
|
|
26657
|
+
|
|
26370
26658
|
// src/commands/connect.ts
|
|
26371
26659
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
26372
26660
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
26661
|
+
init_config();
|
|
26373
26662
|
function openBrowser2(url) {
|
|
26374
26663
|
try {
|
|
26375
26664
|
const platform = process.platform;
|
|
@@ -26426,8 +26715,15 @@ function saveCredentials(data) {
|
|
|
26426
26715
|
update.connectedKeyPreview = data.connectedKeyPreview;
|
|
26427
26716
|
if (data.connectedKeyName)
|
|
26428
26717
|
update.connectedKeyName = data.connectedKeyName;
|
|
26429
|
-
if (data.wallets)
|
|
26718
|
+
if (data.wallets) {
|
|
26430
26719
|
update.agentWallets = data.wallets;
|
|
26720
|
+
const currentConfig = loadConfig();
|
|
26721
|
+
if (!currentConfig.wallet) {
|
|
26722
|
+
const solWallet = data.wallets.find((w) => w.chain === "solana" && w.source === "agent");
|
|
26723
|
+
if (solWallet)
|
|
26724
|
+
update.wallet = solWallet.address;
|
|
26725
|
+
}
|
|
26726
|
+
}
|
|
26431
26727
|
saveConfig(update);
|
|
26432
26728
|
}
|
|
26433
26729
|
function registerConnectCommand(program2) {
|
|
@@ -26554,75 +26850,12 @@ Tip: you can also generate a connect link from your Amiko settings`));
|
|
|
26554
26850
|
});
|
|
26555
26851
|
}
|
|
26556
26852
|
|
|
26557
|
-
// src/
|
|
26558
|
-
|
|
26559
|
-
|
|
26560
|
-
function loadAgentConfig() {
|
|
26561
|
-
let dir = process.cwd();
|
|
26562
|
-
const root = resolve("/");
|
|
26563
|
-
while (dir !== root) {
|
|
26564
|
-
const filePath = join3(dir, ".amiko.json");
|
|
26565
|
-
if (existsSync3(filePath)) {
|
|
26566
|
-
try {
|
|
26567
|
-
const raw = readFileSync2(filePath, "utf-8");
|
|
26568
|
-
const parsed = JSON.parse(raw);
|
|
26569
|
-
const config = {};
|
|
26570
|
-
if (parsed.amikoTwinToken)
|
|
26571
|
-
config.twinToken = parsed.amikoTwinToken;
|
|
26572
|
-
if (parsed.amikoTwinId)
|
|
26573
|
-
config.twinId = parsed.amikoTwinId;
|
|
26574
|
-
if (parsed.amikoUserId)
|
|
26575
|
-
config.userId = parsed.amikoUserId;
|
|
26576
|
-
if (parsed.amikoPlatformUrl)
|
|
26577
|
-
config.platformUrl = parsed.amikoPlatformUrl;
|
|
26578
|
-
return Object.keys(config).length > 0 ? config : null;
|
|
26579
|
-
} catch {
|
|
26580
|
-
return null;
|
|
26581
|
-
}
|
|
26582
|
-
}
|
|
26583
|
-
dir = resolve(dir, "..");
|
|
26584
|
-
}
|
|
26585
|
-
return null;
|
|
26586
|
-
}
|
|
26587
|
-
function resolveAuth(cliConfig) {
|
|
26588
|
-
if (cliConfig.agentWallets?.length) {
|
|
26589
|
-
return {
|
|
26590
|
-
mode: "connected",
|
|
26591
|
-
platformUrl: cliConfig.platformUrl,
|
|
26592
|
-
billingBase: cliConfig.billingBase,
|
|
26593
|
-
twinId: cliConfig.twinId,
|
|
26594
|
-
twinToken: cliConfig.twinToken,
|
|
26595
|
-
platformKey: cliConfig.apiKey,
|
|
26596
|
-
privyToken: cliConfig.privyToken,
|
|
26597
|
-
connectedKeyId: cliConfig.connectedKeyId,
|
|
26598
|
-
userId: cliConfig.userId,
|
|
26599
|
-
agentWallets: cliConfig.agentWallets
|
|
26600
|
-
};
|
|
26601
|
-
}
|
|
26602
|
-
if (cliConfig.privyToken && cliConfig.connectedKeyId) {
|
|
26603
|
-
return {
|
|
26604
|
-
mode: "connected",
|
|
26605
|
-
billingBase: cliConfig.billingBase,
|
|
26606
|
-
platformKey: cliConfig.privyToken,
|
|
26607
|
-
privyToken: cliConfig.privyToken,
|
|
26608
|
-
connectedKeyId: cliConfig.connectedKeyId,
|
|
26609
|
-
userId: cliConfig.userId
|
|
26610
|
-
};
|
|
26611
|
-
}
|
|
26612
|
-
const agentConfig = loadAgentConfig();
|
|
26613
|
-
if (agentConfig?.twinToken) {
|
|
26614
|
-
return {
|
|
26615
|
-
mode: "agent",
|
|
26616
|
-
platformUrl: agentConfig.platformUrl,
|
|
26617
|
-
twinId: agentConfig.twinId,
|
|
26618
|
-
twinToken: agentConfig.twinToken,
|
|
26619
|
-
userId: agentConfig.userId
|
|
26620
|
-
};
|
|
26621
|
-
}
|
|
26622
|
-
return { mode: "none" };
|
|
26623
|
-
}
|
|
26853
|
+
// src/commands/credits.ts
|
|
26854
|
+
init_config();
|
|
26855
|
+
init_agent_config();
|
|
26624
26856
|
|
|
26625
26857
|
// src/lib/mpp-topup.ts
|
|
26858
|
+
init_config();
|
|
26626
26859
|
async function mppCreditsTopup(params) {
|
|
26627
26860
|
const config2 = loadConfig();
|
|
26628
26861
|
const mppBase2 = config2.apiBase.replace(/\/$/, "");
|
|
@@ -27011,6 +27244,7 @@ registerDiscoveryCommand(program2);
|
|
|
27011
27244
|
registerMarketplaceCommand(program2);
|
|
27012
27245
|
registerLoginCommand(program2);
|
|
27013
27246
|
registerBridgeCommand(program2);
|
|
27247
|
+
registerSwapCommand(program2);
|
|
27014
27248
|
registerConnectCommand(program2);
|
|
27015
27249
|
registerCreditsCommand(program2);
|
|
27016
27250
|
registerUpdateCommand(program2);
|