@heyamiko/amiko-cli 0.8.4 → 0.9.0-beta.0
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 +36 -23
- package/dist/index.js +466 -924
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,43 +5,25 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
function __accessProp(key) {
|
|
9
|
-
return this[key];
|
|
10
|
-
}
|
|
11
|
-
var __toESMCache_node;
|
|
12
|
-
var __toESMCache_esm;
|
|
13
8
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
-
var canCache = mod != null && typeof mod === "object";
|
|
15
|
-
if (canCache) {
|
|
16
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
-
var cached = cache.get(mod);
|
|
18
|
-
if (cached)
|
|
19
|
-
return cached;
|
|
20
|
-
}
|
|
21
9
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
10
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
11
|
for (let key of __getOwnPropNames(mod))
|
|
24
12
|
if (!__hasOwnProp.call(to, key))
|
|
25
13
|
__defProp(to, key, {
|
|
26
|
-
get:
|
|
14
|
+
get: () => mod[key],
|
|
27
15
|
enumerable: true
|
|
28
16
|
});
|
|
29
|
-
if (canCache)
|
|
30
|
-
cache.set(mod, to);
|
|
31
17
|
return to;
|
|
32
18
|
};
|
|
33
19
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
-
var __returnValue = (v) => v;
|
|
35
|
-
function __exportSetter(name, newValue) {
|
|
36
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
-
}
|
|
38
20
|
var __export = (target, all) => {
|
|
39
21
|
for (var name in all)
|
|
40
22
|
__defProp(target, name, {
|
|
41
23
|
get: all[name],
|
|
42
24
|
enumerable: true,
|
|
43
25
|
configurable: true,
|
|
44
|
-
set:
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
45
27
|
});
|
|
46
28
|
};
|
|
47
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -3533,36 +3515,11 @@ var require_emoji_regex = __commonJS((exports, module) => {
|
|
|
3533
3515
|
};
|
|
3534
3516
|
});
|
|
3535
3517
|
|
|
3536
|
-
// node_modules/mppx/dist/
|
|
3537
|
-
var
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
from: () => from
|
|
3542
|
-
});
|
|
3543
|
-
function from(method) {
|
|
3544
|
-
return method;
|
|
3545
|
-
}
|
|
3546
|
-
function toClient(method, options) {
|
|
3547
|
-
const { context, createCredential } = options;
|
|
3548
|
-
return {
|
|
3549
|
-
...method,
|
|
3550
|
-
context,
|
|
3551
|
-
createCredential
|
|
3552
|
-
};
|
|
3553
|
-
}
|
|
3554
|
-
function toServer(method, options) {
|
|
3555
|
-
const { defaults, html, request, respond, transport, verify } = options;
|
|
3556
|
-
return {
|
|
3557
|
-
...method,
|
|
3558
|
-
defaults,
|
|
3559
|
-
html,
|
|
3560
|
-
request,
|
|
3561
|
-
respond,
|
|
3562
|
-
transport,
|
|
3563
|
-
verify
|
|
3564
|
-
};
|
|
3565
|
-
}
|
|
3518
|
+
// node_modules/mppx/dist/BodyDigest.js
|
|
3519
|
+
var init_BodyDigest = () => {};
|
|
3520
|
+
|
|
3521
|
+
// node_modules/mppx/dist/PaymentRequest.js
|
|
3522
|
+
var init_PaymentRequest = () => {};
|
|
3566
3523
|
|
|
3567
3524
|
// node_modules/mppx/node_modules/zod/v4/core/core.js
|
|
3568
3525
|
function $constructor(name, initializer, params) {
|
|
@@ -16647,8 +16604,89 @@ var init_zod = __esm(() => {
|
|
|
16647
16604
|
init_mini();
|
|
16648
16605
|
});
|
|
16649
16606
|
|
|
16607
|
+
// node_modules/mppx/dist/Challenge.js
|
|
16608
|
+
var Schema;
|
|
16609
|
+
var init_Challenge = __esm(() => {
|
|
16610
|
+
init_zod();
|
|
16611
|
+
Schema = object({
|
|
16612
|
+
description: optional(string2()),
|
|
16613
|
+
digest: optional(string2().check(_regex(/^sha-256=/, "Invalid digest format"))),
|
|
16614
|
+
expires: optional(datetime3()),
|
|
16615
|
+
id: string2(),
|
|
16616
|
+
intent: string2(),
|
|
16617
|
+
method: string2(),
|
|
16618
|
+
opaque: optional(record(string2(), string2())),
|
|
16619
|
+
realm: string2(),
|
|
16620
|
+
request: record(string2(), unknown())
|
|
16621
|
+
});
|
|
16622
|
+
});
|
|
16623
|
+
|
|
16624
|
+
// node_modules/mppx/dist/Credential.js
|
|
16625
|
+
var init_Credential = () => {};
|
|
16626
|
+
|
|
16627
|
+
// node_modules/mppx/dist/Errors.js
|
|
16628
|
+
var init_Errors = () => {};
|
|
16629
|
+
|
|
16630
|
+
// node_modules/mppx/dist/Expires.js
|
|
16631
|
+
var init_Expires = () => {};
|
|
16632
|
+
|
|
16633
|
+
// node_modules/mppx/dist/Method.js
|
|
16634
|
+
var exports_Method = {};
|
|
16635
|
+
__export(exports_Method, {
|
|
16636
|
+
toServer: () => toServer,
|
|
16637
|
+
toClient: () => toClient,
|
|
16638
|
+
from: () => from
|
|
16639
|
+
});
|
|
16640
|
+
function from(method) {
|
|
16641
|
+
return method;
|
|
16642
|
+
}
|
|
16643
|
+
function toClient(method, options) {
|
|
16644
|
+
const { context, createCredential } = options;
|
|
16645
|
+
return {
|
|
16646
|
+
...method,
|
|
16647
|
+
context,
|
|
16648
|
+
createCredential
|
|
16649
|
+
};
|
|
16650
|
+
}
|
|
16651
|
+
function toServer(method, options) {
|
|
16652
|
+
const { defaults, html, request, respond, transport, verify } = options;
|
|
16653
|
+
return {
|
|
16654
|
+
...method,
|
|
16655
|
+
defaults,
|
|
16656
|
+
html,
|
|
16657
|
+
request,
|
|
16658
|
+
respond,
|
|
16659
|
+
transport,
|
|
16660
|
+
verify
|
|
16661
|
+
};
|
|
16662
|
+
}
|
|
16663
|
+
|
|
16664
|
+
// node_modules/mppx/dist/Receipt.js
|
|
16665
|
+
var Schema2;
|
|
16666
|
+
var init_Receipt = __esm(() => {
|
|
16667
|
+
init_zod();
|
|
16668
|
+
Schema2 = object({
|
|
16669
|
+
method: string2(),
|
|
16670
|
+
reference: string2(),
|
|
16671
|
+
externalId: optional(string2()),
|
|
16672
|
+
status: literal("success"),
|
|
16673
|
+
timestamp: datetime3()
|
|
16674
|
+
});
|
|
16675
|
+
});
|
|
16676
|
+
|
|
16677
|
+
// node_modules/mppx/dist/Store.js
|
|
16678
|
+
var init_Store = () => {};
|
|
16679
|
+
|
|
16650
16680
|
// node_modules/mppx/dist/index.js
|
|
16651
16681
|
var init_dist = __esm(() => {
|
|
16682
|
+
init_BodyDigest();
|
|
16683
|
+
init_Challenge();
|
|
16684
|
+
init_Credential();
|
|
16685
|
+
init_Errors();
|
|
16686
|
+
init_Expires();
|
|
16687
|
+
init_PaymentRequest();
|
|
16688
|
+
init_Receipt();
|
|
16689
|
+
init_Store();
|
|
16652
16690
|
init_zod();
|
|
16653
16691
|
});
|
|
16654
16692
|
|
|
@@ -16720,8 +16758,9 @@ var {
|
|
|
16720
16758
|
} = import__.default;
|
|
16721
16759
|
|
|
16722
16760
|
// src/onboarding.ts
|
|
16723
|
-
|
|
16724
|
-
|
|
16761
|
+
async function runOnboarding(_argv) {
|
|
16762
|
+
return false;
|
|
16763
|
+
}
|
|
16725
16764
|
|
|
16726
16765
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
16727
16766
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -17212,191 +17251,75 @@ var chalk = createChalk();
|
|
|
17212
17251
|
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
17213
17252
|
var source_default = chalk;
|
|
17214
17253
|
|
|
17215
|
-
// src/lib/config.ts
|
|
17216
|
-
import { existsSync,
|
|
17217
|
-
import {
|
|
17218
|
-
|
|
17219
|
-
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
apiBase: "https://mpp.amikomarkets.com",
|
|
17223
|
-
billingBase: "https://billing.heyamiko.com",
|
|
17224
|
-
siteBase: "https://platform.heyamiko.com"
|
|
17225
|
-
};
|
|
17226
|
-
var LEGACY_SITE_BASES = new Set([
|
|
17227
|
-
"https://amiko-markets.vercel.app",
|
|
17228
|
-
"https://amiko-markets.vercel.app/"
|
|
17229
|
-
]);
|
|
17230
|
-
function loadConfig() {
|
|
17231
|
-
if (!existsSync(CONFIG_FILE))
|
|
17232
|
-
return { ...DEFAULTS };
|
|
17254
|
+
// src/lib/agent-config.ts
|
|
17255
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17256
|
+
import { join, resolve } from "node:path";
|
|
17257
|
+
var OPENCLAW_FALLBACK_PATH = "/data/.openclaw/workspace/.amiko.json";
|
|
17258
|
+
function tryRead(filePath) {
|
|
17259
|
+
if (!existsSync(filePath))
|
|
17260
|
+
return null;
|
|
17233
17261
|
try {
|
|
17234
|
-
|
|
17235
|
-
const parsed = JSON.parse(raw);
|
|
17236
|
-
return normalizeConfig({ ...DEFAULTS, ...parsed });
|
|
17262
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
17237
17263
|
} catch {
|
|
17238
|
-
return
|
|
17239
|
-
}
|
|
17240
|
-
}
|
|
17241
|
-
function saveConfig(config) {
|
|
17242
|
-
const current = loadConfig();
|
|
17243
|
-
const merged = normalizeConfig({ ...current, ...config });
|
|
17244
|
-
if (!existsSync(CONFIG_DIR))
|
|
17245
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
17246
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + `
|
|
17247
|
-
`);
|
|
17248
|
-
return merged;
|
|
17249
|
-
}
|
|
17250
|
-
function getConfigPath() {
|
|
17251
|
-
return CONFIG_FILE;
|
|
17252
|
-
}
|
|
17253
|
-
function resetConfig() {
|
|
17254
|
-
if (!existsSync(CONFIG_FILE))
|
|
17255
|
-
return false;
|
|
17256
|
-
unlinkSync(CONFIG_FILE);
|
|
17257
|
-
return true;
|
|
17258
|
-
}
|
|
17259
|
-
function getPrivyToken(config) {
|
|
17260
|
-
return config.privyToken;
|
|
17261
|
-
}
|
|
17262
|
-
function normalizeConfig(config) {
|
|
17263
|
-
const normalized = { ...config };
|
|
17264
|
-
const raw = normalized;
|
|
17265
|
-
if (!normalized.privyToken && typeof raw.creatorToken === "string") {
|
|
17266
|
-
normalized.privyToken = raw.creatorToken;
|
|
17267
|
-
delete raw.creatorToken;
|
|
17268
|
-
}
|
|
17269
|
-
if (LEGACY_SITE_BASES.has(normalized.siteBase)) {
|
|
17270
|
-
normalized.siteBase = DEFAULTS.siteBase;
|
|
17264
|
+
return null;
|
|
17271
17265
|
}
|
|
17272
|
-
return normalized;
|
|
17273
17266
|
}
|
|
17274
|
-
|
|
17275
|
-
// src/lib/agent-config.ts
|
|
17276
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
17277
|
-
import { join as join2, resolve } from "node:path";
|
|
17278
|
-
function loadAgentConfig() {
|
|
17279
|
-
const knownPaths = [
|
|
17280
|
-
process.env.OPENCLAW_WORKSPACE_DIR ? join2(process.env.OPENCLAW_WORKSPACE_DIR, ".amiko.json") : "",
|
|
17281
|
-
process.env.OPENCLAW_HOME ? join2(process.env.OPENCLAW_HOME, ".openclaw", "workspace", ".amiko.json") : "",
|
|
17282
|
-
"/data/.openclaw/workspace/.amiko.json",
|
|
17283
|
-
"/data/.amiko.json"
|
|
17284
|
-
].filter(Boolean);
|
|
17285
|
-
for (const p of knownPaths) {
|
|
17286
|
-
const result = tryLoadConfig(p);
|
|
17287
|
-
if (result)
|
|
17288
|
-
return result;
|
|
17289
|
-
}
|
|
17267
|
+
function findAmikoJson() {
|
|
17290
17268
|
let dir = process.cwd();
|
|
17291
17269
|
const root = resolve("/");
|
|
17292
17270
|
while (dir !== root) {
|
|
17293
|
-
const
|
|
17294
|
-
if (
|
|
17295
|
-
return
|
|
17271
|
+
const parsed = tryRead(join(dir, ".amiko.json"));
|
|
17272
|
+
if (parsed)
|
|
17273
|
+
return parsed;
|
|
17296
17274
|
dir = resolve(dir, "..");
|
|
17297
17275
|
}
|
|
17298
|
-
return
|
|
17276
|
+
return tryRead(OPENCLAW_FALLBACK_PATH);
|
|
17299
17277
|
}
|
|
17300
|
-
function
|
|
17301
|
-
|
|
17302
|
-
return null;
|
|
17303
|
-
try {
|
|
17304
|
-
const raw = readFileSync2(filePath, "utf-8");
|
|
17305
|
-
const parsed = JSON.parse(raw);
|
|
17306
|
-
const config = {};
|
|
17307
|
-
config.twinToken = parsed.amikoTwinToken || parsed.AMIKO_TWIN_TOKEN || parsed.AMIKO_USER_TOKEN;
|
|
17308
|
-
config.twinId = parsed.amikoTwinId || parsed.AMIKO_TWIN_ID;
|
|
17309
|
-
config.userId = parsed.amikoUserId || parsed.AMIKO_USER_ID;
|
|
17310
|
-
config.platformUrl = parsed.amikoPlatformUrl || parsed.AMIKO_PLATFORM_URL;
|
|
17311
|
-
if (parsed.billingBase)
|
|
17312
|
-
config.billingBase = parsed.billingBase;
|
|
17313
|
-
if (parsed.platformKey)
|
|
17314
|
-
config.platformKey = parsed.platformKey;
|
|
17315
|
-
if (Array.isArray(parsed.agentWallets))
|
|
17316
|
-
config.agentWallets = parsed.agentWallets;
|
|
17317
|
-
return Object.keys(config).length > 0 ? config : null;
|
|
17318
|
-
} catch {
|
|
17319
|
-
return null;
|
|
17320
|
-
}
|
|
17278
|
+
function asString(v) {
|
|
17279
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
17321
17280
|
}
|
|
17322
|
-
function resolveAuth(
|
|
17323
|
-
const
|
|
17324
|
-
if (
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17329
|
-
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
|
|
17334
|
-
|
|
17335
|
-
|
|
17336
|
-
|
|
17337
|
-
|
|
17338
|
-
|
|
17339
|
-
if (agentConfig?.platformKey && !cliConfig.apiKey) {
|
|
17340
|
-
cliConfig.apiKey = agentConfig.platformKey;
|
|
17341
|
-
}
|
|
17342
|
-
if (cliConfig.agentWallets?.length) {
|
|
17343
|
-
return {
|
|
17344
|
-
mode: "connected",
|
|
17345
|
-
platformUrl: cliConfig.platformUrl,
|
|
17346
|
-
billingBase: cliConfig.billingBase,
|
|
17347
|
-
twinId: cliConfig.twinId,
|
|
17348
|
-
twinToken: cliConfig.twinToken,
|
|
17349
|
-
platformKey: cliConfig.apiKey,
|
|
17350
|
-
privyToken: cliConfig.privyToken,
|
|
17351
|
-
connectedKeyId: cliConfig.connectedKeyId,
|
|
17352
|
-
userId: cliConfig.userId,
|
|
17353
|
-
agentWallets: cliConfig.agentWallets
|
|
17354
|
-
};
|
|
17355
|
-
}
|
|
17356
|
-
if (cliConfig.privyToken && cliConfig.connectedKeyId) {
|
|
17357
|
-
return {
|
|
17358
|
-
mode: "connected",
|
|
17359
|
-
billingBase: cliConfig.billingBase,
|
|
17360
|
-
platformKey: cliConfig.privyToken,
|
|
17361
|
-
privyToken: cliConfig.privyToken,
|
|
17362
|
-
connectedKeyId: cliConfig.connectedKeyId,
|
|
17363
|
-
userId: cliConfig.userId
|
|
17364
|
-
};
|
|
17365
|
-
}
|
|
17366
|
-
if (cliConfig.apiKey) {
|
|
17367
|
-
return {
|
|
17368
|
-
mode: "connected",
|
|
17369
|
-
billingBase: cliConfig.billingBase,
|
|
17370
|
-
platformKey: cliConfig.apiKey,
|
|
17371
|
-
userId: cliConfig.userId,
|
|
17372
|
-
twinId: cliConfig.twinId,
|
|
17373
|
-
twinToken: cliConfig.twinToken
|
|
17374
|
-
};
|
|
17375
|
-
}
|
|
17376
|
-
const envToken = process.env.AMIKO_USER_TOKEN;
|
|
17377
|
-
if (envToken) {
|
|
17378
|
-
return {
|
|
17379
|
-
mode: "agent",
|
|
17380
|
-
twinId: process.env.AMIKO_TWIN_ID,
|
|
17381
|
-
twinToken: envToken,
|
|
17382
|
-
userId: process.env.AMIKO_USER_ID,
|
|
17383
|
-
billingBase: process.env.API_SERVICE_URL || process.env.BILLING_BASE,
|
|
17384
|
-
platformUrl: process.env.AMIKO_PLATFORM_URL
|
|
17385
|
-
};
|
|
17281
|
+
function resolveAuth() {
|
|
17282
|
+
const parsed = findAmikoJson();
|
|
17283
|
+
if (!parsed)
|
|
17284
|
+
return {};
|
|
17285
|
+
return {
|
|
17286
|
+
twinToken: asString(parsed.amikoTwinToken) ?? asString(parsed.AMIKO_TWIN_TOKEN) ?? asString(parsed.AMIKO_USER_TOKEN),
|
|
17287
|
+
twinId: asString(parsed.amikoTwinId) ?? asString(parsed.AMIKO_TWIN_ID),
|
|
17288
|
+
userId: asString(parsed.amikoUserId) ?? asString(parsed.AMIKO_USER_ID),
|
|
17289
|
+
platformUrl: asString(parsed.amikoPlatformUrl) ?? asString(parsed.AMIKO_PLATFORM_URL),
|
|
17290
|
+
billingBase: asString(parsed.billingBase),
|
|
17291
|
+
apiBase: asString(parsed.apiBase)
|
|
17292
|
+
};
|
|
17293
|
+
}
|
|
17294
|
+
function requireAuth() {
|
|
17295
|
+
const auth = resolveAuth();
|
|
17296
|
+
if (!auth.twinToken) {
|
|
17297
|
+
throw new Error("No twin token found. Place an .amiko.json file with amikoTwinToken in the current directory or any parent (or at /data/.openclaw/workspace/.amiko.json).");
|
|
17386
17298
|
}
|
|
17387
|
-
if (
|
|
17388
|
-
|
|
17389
|
-
mode: "agent",
|
|
17390
|
-
platformUrl: agentConfig.platformUrl,
|
|
17391
|
-
billingBase: agentConfig.billingBase,
|
|
17392
|
-
twinId: agentConfig.twinId,
|
|
17393
|
-
twinToken: agentConfig.twinToken,
|
|
17394
|
-
platformKey: agentConfig.platformKey,
|
|
17395
|
-
userId: agentConfig.userId,
|
|
17396
|
-
agentWallets: agentConfig.agentWallets
|
|
17397
|
-
};
|
|
17299
|
+
if (!auth.twinId) {
|
|
17300
|
+
throw new Error("No twin id in .amiko.json. Add amikoTwinId alongside amikoTwinToken.");
|
|
17398
17301
|
}
|
|
17399
|
-
return
|
|
17302
|
+
return auth;
|
|
17303
|
+
}
|
|
17304
|
+
|
|
17305
|
+
// src/lib/config.ts
|
|
17306
|
+
var DEFAULTS = {
|
|
17307
|
+
apiBase: "https://mpp.amikomarkets.com",
|
|
17308
|
+
billingBase: "https://billing.heyamiko.com",
|
|
17309
|
+
platformUrl: "https://platform.heyamiko.com",
|
|
17310
|
+
siteBase: "https://platform.heyamiko.com"
|
|
17311
|
+
};
|
|
17312
|
+
function loadConfig() {
|
|
17313
|
+
const auth = resolveAuth();
|
|
17314
|
+
return {
|
|
17315
|
+
apiBase: auth.apiBase ?? DEFAULTS.apiBase,
|
|
17316
|
+
billingBase: auth.billingBase ?? DEFAULTS.billingBase,
|
|
17317
|
+
platformUrl: auth.platformUrl ?? DEFAULTS.platformUrl,
|
|
17318
|
+
siteBase: DEFAULTS.siteBase,
|
|
17319
|
+
twinToken: auth.twinToken,
|
|
17320
|
+
twinId: auth.twinId,
|
|
17321
|
+
userId: auth.userId
|
|
17322
|
+
};
|
|
17400
17323
|
}
|
|
17401
17324
|
|
|
17402
17325
|
// src/lib/format.ts
|
|
@@ -17453,164 +17376,27 @@ function renderOutput(data, human, opts = {}) {
|
|
|
17453
17376
|
human(data);
|
|
17454
17377
|
}
|
|
17455
17378
|
|
|
17456
|
-
// src/onboarding.ts
|
|
17457
|
-
var SKIP_COMMANDS = new Set([
|
|
17458
|
-
"help",
|
|
17459
|
-
"--help",
|
|
17460
|
-
"-h",
|
|
17461
|
-
"--version",
|
|
17462
|
-
"-V",
|
|
17463
|
-
"config",
|
|
17464
|
-
"login",
|
|
17465
|
-
"logout",
|
|
17466
|
-
"whoami",
|
|
17467
|
-
"connect",
|
|
17468
|
-
"credits",
|
|
17469
|
-
"swap",
|
|
17470
|
-
"wallet",
|
|
17471
|
-
"bridge",
|
|
17472
|
-
"browse",
|
|
17473
|
-
"call",
|
|
17474
|
-
"update"
|
|
17475
|
-
]);
|
|
17476
|
-
function prompt(question) {
|
|
17477
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
17478
|
-
return new Promise((resolve2) => {
|
|
17479
|
-
rl.question(question, (answer) => {
|
|
17480
|
-
rl.close();
|
|
17481
|
-
resolve2(answer.trim());
|
|
17482
|
-
});
|
|
17483
|
-
});
|
|
17484
|
-
}
|
|
17485
|
-
async function runOnboarding(argv) {
|
|
17486
|
-
const cmd = argv[2];
|
|
17487
|
-
if (cmd && SKIP_COMMANDS.has(cmd))
|
|
17488
|
-
return false;
|
|
17489
|
-
const config = loadConfig();
|
|
17490
|
-
if (config.wallet || config.privyToken || config.apiKey || config.twinToken || config.agentWallets?.length)
|
|
17491
|
-
return false;
|
|
17492
|
-
const auth = resolveAuth(config);
|
|
17493
|
-
if (auth.mode !== "none")
|
|
17494
|
-
return false;
|
|
17495
|
-
console.log("");
|
|
17496
|
-
console.log(heading("Welcome to Amiko CLI"));
|
|
17497
|
-
console.log(dim("The AI agent marketplace on Tempo"));
|
|
17498
|
-
console.log("");
|
|
17499
|
-
console.log(dim(`Config: ${getConfigPath()}`));
|
|
17500
|
-
console.log("");
|
|
17501
|
-
console.log(source_default.cyan("1/3") + " " + source_default.white("Wallet address"));
|
|
17502
|
-
console.log(dim(" Your Tempo/EVM wallet for payments and bridging."));
|
|
17503
|
-
console.log(dim(" Leave blank to skip — you can set it later with: amiko config set wallet <address>"));
|
|
17504
|
-
console.log("");
|
|
17505
|
-
const wallet = await prompt(source_default.dim(" wallet address: "));
|
|
17506
|
-
if (wallet) {
|
|
17507
|
-
saveConfig({ wallet });
|
|
17508
|
-
console.log(success(`Wallet saved: ${wallet.slice(0, 6)}...${wallet.slice(-4)}`));
|
|
17509
|
-
} else {
|
|
17510
|
-
console.log(dim(" Skipped — no wallet set."));
|
|
17511
|
-
}
|
|
17512
|
-
console.log("");
|
|
17513
|
-
console.log(source_default.cyan("2/3") + " " + source_default.white("Sign in (optional)"));
|
|
17514
|
-
console.log(dim(" Signing in lets you create listings, view earnings, and use auto-pay."));
|
|
17515
|
-
console.log(dim(" Run this anytime: amiko login"));
|
|
17516
|
-
console.log("");
|
|
17517
|
-
const doLogin = await prompt(source_default.dim(" sign in now? [y/N]: "));
|
|
17518
|
-
if (doLogin.toLowerCase() === "y" || doLogin.toLowerCase() === "yes") {
|
|
17519
|
-
console.log("");
|
|
17520
|
-
console.log(dim(" Starting login flow..."));
|
|
17521
|
-
try {
|
|
17522
|
-
execFileSync("amiko", ["login"], { stdio: "inherit" });
|
|
17523
|
-
} catch {
|
|
17524
|
-
console.log(dim(" Login skipped or cancelled."));
|
|
17525
|
-
}
|
|
17526
|
-
} else {
|
|
17527
|
-
console.log(dim(" Skipped — you can sign in later with: amiko login"));
|
|
17528
|
-
}
|
|
17529
|
-
console.log("");
|
|
17530
|
-
console.log(source_default.cyan("3/3") + " " + source_default.white("You're ready"));
|
|
17531
|
-
console.log("");
|
|
17532
|
-
const final = loadConfig();
|
|
17533
|
-
console.log(label(" MPP service", final.apiBase));
|
|
17534
|
-
if (final.wallet)
|
|
17535
|
-
console.log(label(" Wallet", `${final.wallet.slice(0, 6)}...${final.wallet.slice(-4)}`));
|
|
17536
|
-
if (final.privyToken)
|
|
17537
|
-
console.log(label(" Signed in", "yes"));
|
|
17538
|
-
console.log("");
|
|
17539
|
-
console.log(dim(" Quick start:"));
|
|
17540
|
-
console.log(dim(" amiko browse Browse live agents"));
|
|
17541
|
-
console.log(dim(" amiko call <agent> <msg> Call a paid agent"));
|
|
17542
|
-
console.log(dim(" amiko bridge quote 5 Get a bridge quote"));
|
|
17543
|
-
console.log(dim(" amiko wallet balance Check wallet balance"));
|
|
17544
|
-
console.log("");
|
|
17545
|
-
return true;
|
|
17546
|
-
}
|
|
17547
|
-
|
|
17548
17379
|
// src/commands/config.ts
|
|
17549
|
-
var VALID_KEYS = [
|
|
17550
|
-
"apiBase",
|
|
17551
|
-
"billingBase",
|
|
17552
|
-
"siteBase",
|
|
17553
|
-
"platformUrl",
|
|
17554
|
-
"wallet",
|
|
17555
|
-
"apiKey",
|
|
17556
|
-
"privyToken",
|
|
17557
|
-
"userId",
|
|
17558
|
-
"twinId",
|
|
17559
|
-
"twinToken",
|
|
17560
|
-
"connectedKeyId",
|
|
17561
|
-
"connectedKeyName",
|
|
17562
|
-
"connectedKeyPreview"
|
|
17563
|
-
];
|
|
17564
|
-
function maskKey(key) {
|
|
17565
|
-
if (key.length <= 8)
|
|
17566
|
-
return "****";
|
|
17567
|
-
return key.slice(0, 4) + "..." + key.slice(-4);
|
|
17568
|
-
}
|
|
17569
17380
|
function registerConfigCommand(program2) {
|
|
17570
|
-
const cmd = program2.command("config").description("
|
|
17381
|
+
const cmd = program2.command("config").description("Show resolved CLI configuration (from .amiko.json)");
|
|
17571
17382
|
cmd.command("show").description("Show current configuration").action(() => {
|
|
17572
17383
|
const config = loadConfig();
|
|
17573
|
-
const privyToken = getPrivyToken(config);
|
|
17574
17384
|
console.log(heading("Amiko CLI Configuration"));
|
|
17575
|
-
console.log(
|
|
17576
|
-
`));
|
|
17385
|
+
console.log("");
|
|
17577
17386
|
console.log(heading("Endpoints"));
|
|
17578
17387
|
console.log(label(" MPP service", config.apiBase));
|
|
17579
17388
|
console.log(label(" Billing API", config.billingBase));
|
|
17580
|
-
console.log(label("
|
|
17389
|
+
console.log(label(" Platform", config.platformUrl));
|
|
17581
17390
|
console.log("");
|
|
17582
17391
|
console.log(heading("Identity"));
|
|
17583
|
-
console.log(label(" Wallet", config.wallet || source_default.dim("(not set)")));
|
|
17584
|
-
console.log(label(" Signed in", privyToken ? source_default.green("yes") : source_default.dim("no")));
|
|
17585
17392
|
console.log(label(" User ID", config.userId || source_default.dim("(not set)")));
|
|
17586
|
-
console.log(label("
|
|
17587
|
-
console.log(label("
|
|
17588
|
-
|
|
17589
|
-
|
|
17590
|
-
console.log(dim("
|
|
17591
|
-
console.log(dim(" amiko login Sign in with Privy"));
|
|
17592
|
-
console.log(dim(" amiko config set apiKey Set an API key"));
|
|
17593
|
-
}
|
|
17594
|
-
});
|
|
17595
|
-
cmd.command("set").description("Set a configuration value").argument("<key>", `Config key (${VALID_KEYS.join(", ")})`).argument("<value>", "Config value").action((key, value) => {
|
|
17596
|
-
if (!VALID_KEYS.includes(key)) {
|
|
17597
|
-
console.error(source_default.red(`Invalid key "${key}".`));
|
|
17598
|
-
console.log(source_default.dim(`Valid keys: ${VALID_KEYS.join(", ")}`));
|
|
17599
|
-
process.exit(1);
|
|
17600
|
-
}
|
|
17601
|
-
saveConfig({ [key]: value });
|
|
17602
|
-
console.log(source_default.green(`✓ Set ${key}`));
|
|
17603
|
-
});
|
|
17604
|
-
cmd.command("reset").description("Reset configuration to defaults").action(() => {
|
|
17605
|
-
if (resetConfig()) {
|
|
17606
|
-
console.log(source_default.green("✓ Config reset to defaults"));
|
|
17607
|
-
} else {
|
|
17608
|
-
console.log(source_default.dim("Already at defaults."));
|
|
17393
|
+
console.log(label(" Twin ID", config.twinId || source_default.dim("(not set)")));
|
|
17394
|
+
console.log(label(" Twin Token", config.twinToken ? source_default.green("present") : source_default.dim("(not set)")));
|
|
17395
|
+
if (!config.twinToken) {
|
|
17396
|
+
console.log("");
|
|
17397
|
+
console.log(dim("Place .amiko.json with amikoTwinToken in cwd or any parent."));
|
|
17609
17398
|
}
|
|
17610
17399
|
});
|
|
17611
|
-
cmd.command("path").description("Print config file path").action(() => {
|
|
17612
|
-
console.log(getConfigPath());
|
|
17613
|
-
});
|
|
17614
17400
|
}
|
|
17615
17401
|
|
|
17616
17402
|
// node_modules/ora/index.js
|
|
@@ -18495,16 +18281,10 @@ function ora(options) {
|
|
|
18495
18281
|
function mppBase() {
|
|
18496
18282
|
return trimBase(loadConfig().apiBase);
|
|
18497
18283
|
}
|
|
18498
|
-
function authHeaders() {
|
|
18499
|
-
const config = loadConfig();
|
|
18500
|
-
const headers = { "Content-Type": "application/json" };
|
|
18501
|
-
if (config.apiKey) {
|
|
18502
|
-
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
18503
|
-
}
|
|
18504
|
-
return headers;
|
|
18505
|
-
}
|
|
18506
18284
|
async function get(path) {
|
|
18507
|
-
const res = await fetch(`${mppBase()}${path}`, {
|
|
18285
|
+
const res = await fetch(`${mppBase()}${path}`, {
|
|
18286
|
+
headers: { "Content-Type": "application/json" }
|
|
18287
|
+
});
|
|
18508
18288
|
await assertOk(res);
|
|
18509
18289
|
return res.json();
|
|
18510
18290
|
}
|
|
@@ -18606,21 +18386,21 @@ function registerDiscoveryCommand(program2) {
|
|
|
18606
18386
|
}
|
|
18607
18387
|
|
|
18608
18388
|
// src/lib/tempo.ts
|
|
18609
|
-
import { execFile, execFileSync
|
|
18610
|
-
import { existsSync as
|
|
18611
|
-
import { homedir
|
|
18612
|
-
import { join as
|
|
18613
|
-
var TEMPO_PATHS = [
|
|
18389
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
18390
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
18391
|
+
import { homedir } from "node:os";
|
|
18392
|
+
import { join as join2 } from "node:path";
|
|
18393
|
+
var TEMPO_PATHS = [join2(homedir(), ".tempo", "bin", "tempo"), "tempo"];
|
|
18614
18394
|
function findTempo() {
|
|
18615
18395
|
for (const p of TEMPO_PATHS) {
|
|
18616
18396
|
if (p === "tempo") {
|
|
18617
18397
|
try {
|
|
18618
|
-
|
|
18398
|
+
execFileSync(p, ["--version"], { stdio: "pipe", timeout: 3000 });
|
|
18619
18399
|
return p;
|
|
18620
18400
|
} catch {
|
|
18621
18401
|
continue;
|
|
18622
18402
|
}
|
|
18623
|
-
} else if (
|
|
18403
|
+
} else if (existsSync2(p)) {
|
|
18624
18404
|
return p;
|
|
18625
18405
|
}
|
|
18626
18406
|
}
|
|
@@ -18867,10 +18647,10 @@ function registerBridgeCommand(program2) {
|
|
|
18867
18647
|
const inputToken = getUsdcAddress(originChainId);
|
|
18868
18648
|
const outputToken = getUsdcAddress(destChainId);
|
|
18869
18649
|
const amount = parseUsdcAmount(amountStr);
|
|
18870
|
-
const depositor = opts.depositor
|
|
18650
|
+
const depositor = opts.depositor;
|
|
18871
18651
|
if (!depositor) {
|
|
18872
18652
|
spinner.stop();
|
|
18873
|
-
console.error(error("No depositor address. Provide --depositor
|
|
18653
|
+
console.error(error("No depositor address. Provide --depositor <address>."));
|
|
18874
18654
|
process.exit(1);
|
|
18875
18655
|
}
|
|
18876
18656
|
const isCrossEcosystem = originChainId === CHAINS.solana !== (destChainId === CHAINS.solana);
|
|
@@ -18935,10 +18715,10 @@ function registerBridgeCommand(program2) {
|
|
|
18935
18715
|
const inputToken = getUsdcAddress(originChainId);
|
|
18936
18716
|
const outputToken = getUsdcAddress(destChainId);
|
|
18937
18717
|
const amount = parseUsdcAmount(amountStr);
|
|
18938
|
-
const depositor = opts.depositor
|
|
18718
|
+
const depositor = opts.depositor;
|
|
18939
18719
|
if (!depositor) {
|
|
18940
18720
|
spinner.stop();
|
|
18941
|
-
console.error(error("No depositor address. Provide --depositor
|
|
18721
|
+
console.error(error("No depositor address. Provide --depositor <address>."));
|
|
18942
18722
|
process.exit(1);
|
|
18943
18723
|
}
|
|
18944
18724
|
const isCrossEcosystem = originChainId === CHAINS.solana !== (destChainId === CHAINS.solana);
|
|
@@ -19205,11 +18985,9 @@ function baseUrl(auth) {
|
|
|
19205
18985
|
return url.replace(/\/$/, "");
|
|
19206
18986
|
}
|
|
19207
18987
|
function authHeader(auth) {
|
|
19208
|
-
if (auth.privyToken)
|
|
19209
|
-
return `Bearer am-${auth.privyToken}`;
|
|
19210
18988
|
if (auth.twinToken)
|
|
19211
18989
|
return `Bearer ${auth.twinToken}`;
|
|
19212
|
-
throw new Error("No
|
|
18990
|
+
throw new Error("No twin token found. Place an .amiko.json file with amikoTwinToken in the current directory or any parent.");
|
|
19213
18991
|
}
|
|
19214
18992
|
async function amikoWebFetch(auth, path, opts = {}) {
|
|
19215
18993
|
const url = new URL(`${baseUrl(auth)}${path}`);
|
|
@@ -19275,6 +19053,34 @@ function formatError(status, body, path) {
|
|
|
19275
19053
|
return `${prefix}: ${snippet}`;
|
|
19276
19054
|
}
|
|
19277
19055
|
|
|
19056
|
+
// src/lib/balance.ts
|
|
19057
|
+
async function fetchCreditsBalance(auth) {
|
|
19058
|
+
if (!auth.twinToken)
|
|
19059
|
+
return null;
|
|
19060
|
+
const base = (auth.billingBase || "https://billing.heyamiko.com").replace(/\/$/, "");
|
|
19061
|
+
try {
|
|
19062
|
+
const res = await fetch(`${base}/api/credits`, {
|
|
19063
|
+
headers: { Authorization: `Bearer ${auth.twinToken}` }
|
|
19064
|
+
});
|
|
19065
|
+
if (!res.ok)
|
|
19066
|
+
return null;
|
|
19067
|
+
const data = await res.json();
|
|
19068
|
+
const raw = data.displayBalance ?? Number(data.credits?.balance ?? 0);
|
|
19069
|
+
return typeof raw === "number" && isFinite(raw) ? Math.round(raw) : null;
|
|
19070
|
+
} catch {
|
|
19071
|
+
return null;
|
|
19072
|
+
}
|
|
19073
|
+
}
|
|
19074
|
+
async function printBalanceRemaining(auth) {
|
|
19075
|
+
const balance = await fetchCreditsBalance(auth);
|
|
19076
|
+
if (balance == null) {
|
|
19077
|
+
console.log(dim("Balance: (could not fetch)"));
|
|
19078
|
+
return;
|
|
19079
|
+
}
|
|
19080
|
+
const usd2 = (balance / 1e4).toFixed(2);
|
|
19081
|
+
console.log(label("Balance", `${balance.toLocaleString()} credits (~$${usd2})`));
|
|
19082
|
+
}
|
|
19083
|
+
|
|
19278
19084
|
// src/lib/mpp-topup.ts
|
|
19279
19085
|
async function mppCreditsTopup(params) {
|
|
19280
19086
|
const config2 = loadConfig();
|
|
@@ -19302,9 +19108,6 @@ async function mppCreditsTopup(params) {
|
|
|
19302
19108
|
} catch {
|
|
19303
19109
|
try {
|
|
19304
19110
|
const headers = { "Content-Type": "application/json" };
|
|
19305
|
-
if (config2.apiKey) {
|
|
19306
|
-
headers["Authorization"] = `Bearer ${config2.apiKey}`;
|
|
19307
|
-
}
|
|
19308
19111
|
const res = await fetch(`${base}/v1/credits/topup`, {
|
|
19309
19112
|
method: "POST",
|
|
19310
19113
|
headers,
|
|
@@ -19337,9 +19140,8 @@ async function mppCreditsTopup(params) {
|
|
|
19337
19140
|
|
|
19338
19141
|
// src/commands/credits.ts
|
|
19339
19142
|
function promptYesNo2(question) {
|
|
19340
|
-
if (!process.stdin.isTTY)
|
|
19143
|
+
if (!process.stdin.isTTY)
|
|
19341
19144
|
return Promise.resolve(false);
|
|
19342
|
-
}
|
|
19343
19145
|
const rl = readline2.createInterface({
|
|
19344
19146
|
input: process.stdin,
|
|
19345
19147
|
output: process.stdout
|
|
@@ -19353,114 +19155,25 @@ function promptYesNo2(question) {
|
|
|
19353
19155
|
}
|
|
19354
19156
|
function registerCreditsCommand(program2) {
|
|
19355
19157
|
const credits = program2.command("credits").description("Manage Amiko credit balance and top-ups");
|
|
19356
|
-
credits.command("balance").description("Show credit balance
|
|
19357
|
-
const
|
|
19358
|
-
|
|
19359
|
-
|
|
19360
|
-
if (auth.mode === "none") {
|
|
19361
|
-
spinner.stop();
|
|
19362
|
-
console.error(error("Not authenticated. Check .amiko.json credentials."));
|
|
19363
|
-
process.exit(1);
|
|
19364
|
-
}
|
|
19365
|
-
spinner.stop();
|
|
19366
|
-
console.log(heading("Credits"));
|
|
19367
|
-
console.log("");
|
|
19368
|
-
{
|
|
19369
|
-
const spinner2 = ora("Fetching credit balance...").start();
|
|
19370
|
-
try {
|
|
19371
|
-
let balance = null;
|
|
19372
|
-
const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
|
|
19373
|
-
const base = auth.billingBase || "https://billing.heyamiko.com";
|
|
19374
|
-
if (billingToken) {
|
|
19375
|
-
try {
|
|
19376
|
-
const res = await fetch(`${base}/api/credits`, {
|
|
19377
|
-
headers: {
|
|
19378
|
-
Authorization: `Bearer ${billingToken}`
|
|
19379
|
-
}
|
|
19380
|
-
});
|
|
19381
|
-
if (res.ok) {
|
|
19382
|
-
const data = await res.json();
|
|
19383
|
-
balance = data.displayBalance ?? Math.round(Number(data.credits?.balance || 0));
|
|
19384
|
-
} else {
|
|
19385
|
-
console.log(dim(` API returned ${res.status}: ${await res.text().catch(() => "")}`));
|
|
19386
|
-
}
|
|
19387
|
-
} catch (e) {
|
|
19388
|
-
console.log(dim(` Fetch error: ${e.message}`));
|
|
19389
|
-
}
|
|
19390
|
-
} else {
|
|
19391
|
-
console.log(dim(" No auth token available"));
|
|
19392
|
-
}
|
|
19393
|
-
spinner2.stop();
|
|
19394
|
-
if (balance !== null) {
|
|
19395
|
-
console.log(label("Balance", source_default.bold(balance.toLocaleString()) + " credits"));
|
|
19396
|
-
console.log("");
|
|
19397
|
-
} else {
|
|
19398
|
-
console.log(dim(" Could not fetch credit balance"));
|
|
19399
|
-
console.log("");
|
|
19400
|
-
}
|
|
19401
|
-
} catch (err) {
|
|
19402
|
-
spinner2.stop();
|
|
19403
|
-
console.error(error(err instanceof Error ? err.message : "Failed to fetch credit balance"));
|
|
19404
|
-
}
|
|
19405
|
-
}
|
|
19406
|
-
const agentWallets = (auth.agentWallets || []).filter((w) => w.source === "agent");
|
|
19407
|
-
if (agentWallets.length > 0) {
|
|
19408
|
-
const spinner3 = ora("Fetching wallet balances...").start();
|
|
19409
|
-
try {
|
|
19410
|
-
spinner3.stop();
|
|
19411
|
-
console.log(label("Agent Wallets", ""));
|
|
19412
|
-
for (const w of agentWallets) {
|
|
19413
|
-
const addr = w.address || "";
|
|
19414
|
-
const chain = w.chain || "solana";
|
|
19415
|
-
const isEvm = [
|
|
19416
|
-
"base",
|
|
19417
|
-
"ethereum",
|
|
19418
|
-
"tempo"
|
|
19419
|
-
].includes(chain);
|
|
19420
|
-
const chainLabel = isEvm ? "EVM (Ethereum · Base · Tempo)" : chain.charAt(0).toUpperCase() + chain.slice(1);
|
|
19421
|
-
const shortAddr = addr || "";
|
|
19422
|
-
console.log(` ${source_default.bold(chainLabel)} ${dim(shortAddr)}`);
|
|
19423
|
-
if (!auth.twinId) {
|
|
19424
|
-
console.log(dim(" (no twin id for balance fetch)"));
|
|
19425
|
-
continue;
|
|
19426
|
-
}
|
|
19427
|
-
try {
|
|
19428
|
-
const balData = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(addr)}/balance`);
|
|
19429
|
-
if (balData.chains) {
|
|
19430
|
-
for (const [chainName, chainBals] of Object.entries(balData.chains)) {
|
|
19431
|
-
const rows = Object.entries(chainBals).filter(([, t]) => parseFloat(t.amount) > 0);
|
|
19432
|
-
if (rows.length === 0)
|
|
19433
|
-
continue;
|
|
19434
|
-
console.log(dim(` ${chainName}`));
|
|
19435
|
-
for (const [token, tData] of rows) {
|
|
19436
|
-
const human = parseFloat(tData.amount) / Math.pow(10, tData.decimals);
|
|
19437
|
-
console.log(dim(` ${token.padEnd(10)} ${human.toFixed(6)}`));
|
|
19438
|
-
}
|
|
19439
|
-
}
|
|
19440
|
-
} else {
|
|
19441
|
-
for (const [token, tData] of Object.entries(balData.balances || {})) {
|
|
19442
|
-
const human = parseFloat(tData.amount) / Math.pow(10, tData.decimals);
|
|
19443
|
-
console.log(dim(` ${token.padEnd(10)} ${human.toFixed(6)}`));
|
|
19444
|
-
}
|
|
19445
|
-
}
|
|
19446
|
-
} catch (e) {
|
|
19447
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
19448
|
-
console.log(dim(` (balance fetch failed: ${msg.slice(0, 80)})`));
|
|
19449
|
-
}
|
|
19450
|
-
}
|
|
19451
|
-
console.log("");
|
|
19452
|
-
} catch (err) {
|
|
19453
|
-
spinner3.stop();
|
|
19454
|
-
console.error(error(err instanceof Error ? err.message : "Failed to fetch wallet balances"));
|
|
19455
|
-
}
|
|
19456
|
-
}
|
|
19457
|
-
} catch (err) {
|
|
19458
|
-
spinner.stop();
|
|
19459
|
-
console.error(error(err instanceof Error ? err.message : "Failed to fetch balances"));
|
|
19158
|
+
credits.command("balance").description("Show credit balance").action(async () => {
|
|
19159
|
+
const auth = resolveAuth();
|
|
19160
|
+
if (!auth.twinToken) {
|
|
19161
|
+
console.error(error("Not authenticated. Place .amiko.json with amikoTwinToken in cwd or any parent."));
|
|
19460
19162
|
process.exit(1);
|
|
19461
19163
|
}
|
|
19164
|
+
const spinner = ora("Fetching balance...").start();
|
|
19165
|
+
const balance = await fetchCreditsBalance(auth);
|
|
19166
|
+
spinner.stop();
|
|
19167
|
+
console.log(heading("Credits"));
|
|
19168
|
+
console.log("");
|
|
19169
|
+
if (balance == null) {
|
|
19170
|
+
console.log(dim(" Could not fetch credit balance"));
|
|
19171
|
+
return;
|
|
19172
|
+
}
|
|
19173
|
+
const usd2 = (balance / 1e4).toFixed(2);
|
|
19174
|
+
console.log(label("Balance", `${source_default.bold(balance.toLocaleString())} credits (~$${usd2})`));
|
|
19462
19175
|
});
|
|
19463
|
-
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("--usd <amount>", "Amount in USD instead of credits (e.g. --usd 1
|
|
19176
|
+
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) => {
|
|
19464
19177
|
const inputs = [amountStr, options.usd, options.spend].filter((v) => v != null && v !== "");
|
|
19465
19178
|
if (inputs.length !== 1) {
|
|
19466
19179
|
console.error(error("Specify exactly one of: <amount> (credits), --usd <dollars>, or --spend <token amount>."));
|
|
@@ -19495,224 +19208,152 @@ function registerCreditsCommand(program2) {
|
|
|
19495
19208
|
}
|
|
19496
19209
|
presetCredits = credits2;
|
|
19497
19210
|
}
|
|
19498
|
-
|
|
19211
|
+
let auth;
|
|
19499
19212
|
try {
|
|
19500
|
-
|
|
19501
|
-
|
|
19502
|
-
|
|
19503
|
-
|
|
19504
|
-
|
|
19505
|
-
|
|
19506
|
-
|
|
19507
|
-
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
const
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
|
|
19521
|
-
};
|
|
19522
|
-
spinner.stop();
|
|
19523
|
-
const token = options.token || "AMIKO";
|
|
19524
|
-
const stablecoins = ["usdc", "usdt", "usdc.e", "usdt0"];
|
|
19525
|
-
const isStable = stablecoins.includes(token.toLowerCase());
|
|
19526
|
-
let pricePerToken = null;
|
|
19527
|
-
if (isStable) {
|
|
19528
|
-
pricePerToken = 1;
|
|
19529
|
-
} else {
|
|
19530
|
-
const spinner2 = ora(`Fetching ${token} price...`).start();
|
|
19531
|
-
try {
|
|
19532
|
-
const MINTS = {
|
|
19533
|
-
AMIKO: "AY1Ww6MxwC3cCiyrandHqLrp4FXvzgcwQTZpJ2FEpump",
|
|
19534
|
-
SOL: "So11111111111111111111111111111111111111112"
|
|
19535
|
-
};
|
|
19536
|
-
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
19537
|
-
const mint = MINTS[token.toUpperCase()];
|
|
19538
|
-
if (!mint) {
|
|
19539
|
-
spinner2.stop();
|
|
19540
|
-
console.error(error(`Unknown token: ${token}`));
|
|
19541
|
-
process.exit(1);
|
|
19542
|
-
}
|
|
19543
|
-
const decimals = token.toUpperCase() === "SOL" ? 9 : 6;
|
|
19544
|
-
const oneToken = Math.pow(10, decimals).toString();
|
|
19545
|
-
const jupRes = await fetch(`https://lite-api.jup.ag/swap/v1/quote?inputMint=${mint}&outputMint=${USDC_MINT}&amount=${oneToken}&slippageBps=100`);
|
|
19546
|
-
if (!jupRes.ok) {
|
|
19547
|
-
spinner2.stop();
|
|
19548
|
-
console.error(error("Failed to fetch token price"));
|
|
19549
|
-
process.exit(1);
|
|
19550
|
-
}
|
|
19551
|
-
const jupData = await jupRes.json();
|
|
19552
|
-
pricePerToken = parseFloat(jupData.outAmount) / 1e6;
|
|
19213
|
+
auth = requireAuth();
|
|
19214
|
+
} catch (e) {
|
|
19215
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
19216
|
+
process.exit(1);
|
|
19217
|
+
}
|
|
19218
|
+
const token = options.token || "AMIKO";
|
|
19219
|
+
const stablecoins = ["usdc", "usdt", "usdc.e", "usdt0"];
|
|
19220
|
+
const isStable = stablecoins.includes(token.toLowerCase());
|
|
19221
|
+
let pricePerToken = null;
|
|
19222
|
+
if (isStable) {
|
|
19223
|
+
pricePerToken = 1;
|
|
19224
|
+
} else {
|
|
19225
|
+
const spinner2 = ora(`Fetching ${token} price...`).start();
|
|
19226
|
+
try {
|
|
19227
|
+
const MINTS = {
|
|
19228
|
+
AMIKO: "AY1Ww6MxwC3cCiyrandHqLrp4FXvzgcwQTZpJ2FEpump",
|
|
19229
|
+
SOL: "So11111111111111111111111111111111111111112"
|
|
19230
|
+
};
|
|
19231
|
+
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
19232
|
+
const mint = MINTS[token.toUpperCase()];
|
|
19233
|
+
if (!mint) {
|
|
19553
19234
|
spinner2.stop();
|
|
19554
|
-
|
|
19235
|
+
console.error(error(`Unknown token: ${token}`));
|
|
19236
|
+
process.exit(1);
|
|
19237
|
+
}
|
|
19238
|
+
const decimals = token.toUpperCase() === "SOL" ? 9 : 6;
|
|
19239
|
+
const oneToken = Math.pow(10, decimals).toString();
|
|
19240
|
+
const jupRes = await fetch(`https://lite-api.jup.ag/swap/v1/quote?inputMint=${mint}&outputMint=${USDC_MINT}&amount=${oneToken}&slippageBps=100`);
|
|
19241
|
+
if (!jupRes.ok) {
|
|
19555
19242
|
spinner2.stop();
|
|
19556
19243
|
console.error(error("Failed to fetch token price"));
|
|
19557
19244
|
process.exit(1);
|
|
19558
19245
|
}
|
|
19559
|
-
|
|
19560
|
-
|
|
19561
|
-
let usdAmount;
|
|
19562
|
-
let tokenAmount;
|
|
19563
|
-
if (presetSpend != null) {
|
|
19564
|
-
tokenAmount = presetSpend;
|
|
19565
|
-
usdAmount = tokenAmount * pricePerToken;
|
|
19566
|
-
creditsAmount = Math.round(usdAmount * 1e4);
|
|
19567
|
-
} else if (presetUsd != null) {
|
|
19568
|
-
usdAmount = presetUsd;
|
|
19569
|
-
creditsAmount = Math.round(usdAmount * 1e4);
|
|
19570
|
-
tokenAmount = usdAmount / pricePerToken;
|
|
19571
|
-
} else {
|
|
19572
|
-
creditsAmount = presetCredits;
|
|
19573
|
-
usdAmount = creditsAmount / 1e4;
|
|
19574
|
-
tokenAmount = usdAmount / pricePerToken;
|
|
19575
|
-
}
|
|
19576
|
-
if (options.method === "mpp" && auth.userId && auth.connectedKeyId) {
|
|
19577
|
-
if (!options.yes) {
|
|
19578
|
-
console.log(heading("Top-up Summary (MPP)"));
|
|
19579
|
-
console.log("");
|
|
19580
|
-
console.log(label("Credits", creditsAmount.toLocaleString()));
|
|
19581
|
-
console.log(label("USD", `$${usdAmount.toFixed(2)}`));
|
|
19582
|
-
console.log(dim("Charged via MPP connected key."));
|
|
19583
|
-
console.log("");
|
|
19584
|
-
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
19585
|
-
if (!ok) {
|
|
19586
|
-
console.log(dim("Top-up cancelled."));
|
|
19587
|
-
process.exit(0);
|
|
19588
|
-
}
|
|
19589
|
-
console.log("");
|
|
19590
|
-
}
|
|
19591
|
-
const spinner2 = ora("Topping up credits via MPP...").start();
|
|
19592
|
-
const mppResult = await mppCreditsTopup({
|
|
19593
|
-
userId: auth.userId,
|
|
19594
|
-
keyId: auth.connectedKeyId,
|
|
19595
|
-
amount: usdAmount
|
|
19596
|
-
});
|
|
19246
|
+
const jupData = await jupRes.json();
|
|
19247
|
+
pricePerToken = parseFloat(jupData.outAmount) / 1e6;
|
|
19597
19248
|
spinner2.stop();
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
console.log(heading("Top-up Complete (MPP)"));
|
|
19603
|
-
console.log("");
|
|
19604
|
-
if (mppResult.credits?.balance)
|
|
19605
|
-
console.log(label("Balance", String(mppResult.credits.balance)));
|
|
19606
|
-
console.log(success("Credits topped up via MPP."));
|
|
19607
|
-
return;
|
|
19249
|
+
} catch {
|
|
19250
|
+
spinner2.stop();
|
|
19251
|
+
console.error(error("Failed to fetch token price"));
|
|
19252
|
+
process.exit(1);
|
|
19608
19253
|
}
|
|
19609
|
-
|
|
19610
|
-
|
|
19611
|
-
|
|
19612
|
-
|
|
19613
|
-
|
|
19254
|
+
}
|
|
19255
|
+
let creditsAmount;
|
|
19256
|
+
let usdAmount;
|
|
19257
|
+
let tokenAmount;
|
|
19258
|
+
if (presetSpend != null) {
|
|
19259
|
+
tokenAmount = presetSpend;
|
|
19260
|
+
usdAmount = tokenAmount * pricePerToken;
|
|
19261
|
+
creditsAmount = Math.round(usdAmount * 1e4);
|
|
19262
|
+
} else if (presetUsd != null) {
|
|
19263
|
+
usdAmount = presetUsd;
|
|
19264
|
+
creditsAmount = Math.round(usdAmount * 1e4);
|
|
19265
|
+
tokenAmount = usdAmount / pricePerToken;
|
|
19266
|
+
} else {
|
|
19267
|
+
creditsAmount = presetCredits;
|
|
19268
|
+
usdAmount = creditsAmount / 1e4;
|
|
19269
|
+
tokenAmount = usdAmount / pricePerToken;
|
|
19270
|
+
}
|
|
19271
|
+
if (options.method === "mpp") {
|
|
19272
|
+
if (!auth.userId) {
|
|
19273
|
+
console.error(error("--method mpp requires amikoUserId in .amiko.json."));
|
|
19614
19274
|
process.exit(1);
|
|
19615
19275
|
}
|
|
19616
|
-
|
|
19617
|
-
|
|
19618
|
-
|
|
19619
|
-
console.log(label("Credits", creditsAmount.toLocaleString()));
|
|
19620
|
-
console.log(label("Cost", `${tokenAmount.toFixed(6)} ${token} (~$${usdAmount.toFixed(2)})`));
|
|
19621
|
-
if (pricePerToken && pricePerToken !== 1) {
|
|
19622
|
-
console.log(label("Price", `1 ${token} = $${pricePerToken.toFixed(4)}`));
|
|
19276
|
+
if (!options.keyId) {
|
|
19277
|
+
console.error(error("--method mpp requires --key-id <platformKeyId>."));
|
|
19278
|
+
process.exit(1);
|
|
19623
19279
|
}
|
|
19624
|
-
console.log(label("From", `wallet ${shortWallet} (${walletChain})`));
|
|
19625
|
-
console.log(dim("Tokens will be transferred from your agent wallet to the treasury."));
|
|
19626
|
-
console.log("");
|
|
19627
19280
|
if (!options.yes) {
|
|
19628
|
-
|
|
19629
|
-
|
|
19281
|
+
console.log(heading("Top-up Summary (MPP)"));
|
|
19282
|
+
console.log("");
|
|
19283
|
+
console.log(label("Credits", creditsAmount.toLocaleString()));
|
|
19284
|
+
console.log(label("USD", `$${usdAmount.toFixed(2)}`));
|
|
19285
|
+
console.log(dim("Charged via MPP connected key."));
|
|
19286
|
+
console.log("");
|
|
19287
|
+
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
19288
|
+
if (!ok) {
|
|
19630
19289
|
console.log(dim("Top-up cancelled."));
|
|
19631
19290
|
process.exit(0);
|
|
19632
19291
|
}
|
|
19633
19292
|
console.log("");
|
|
19634
19293
|
}
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
const spinner3 = ora("Transferring tokens to treasury...").start();
|
|
19641
|
-
const transferRes = await fetch(`${auth.billingBase || "https://billing.heyamiko.com"}/api/crossmint/wallets/${encodeURIComponent(walletAddr)}/transfer`, {
|
|
19642
|
-
method: "POST",
|
|
19643
|
-
headers: authHeaders2,
|
|
19644
|
-
body: JSON.stringify({
|
|
19645
|
-
to: TREASURY,
|
|
19646
|
-
amount: tokenAmount.toFixed(6),
|
|
19647
|
-
token,
|
|
19648
|
-
chain: walletChain
|
|
19649
|
-
})
|
|
19294
|
+
const spinner2 = ora("Topping up credits via MPP...").start();
|
|
19295
|
+
const mppResult = await mppCreditsTopup({
|
|
19296
|
+
userId: auth.userId,
|
|
19297
|
+
keyId: options.keyId,
|
|
19298
|
+
amount: usdAmount
|
|
19650
19299
|
});
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
console.error(error(err.error || `Transfer failed: ${transferRes.status}`));
|
|
19655
|
-
if (err.details) {
|
|
19656
|
-
console.error(dim(typeof err.details === "string" ? err.details : JSON.stringify(err.details)));
|
|
19657
|
-
}
|
|
19658
|
-
process.exit(1);
|
|
19659
|
-
}
|
|
19660
|
-
const transferData = await transferRes.json();
|
|
19661
|
-
const txHash = transferData.txHash;
|
|
19662
|
-
spinner3.stop();
|
|
19663
|
-
if (!txHash) {
|
|
19664
|
-
console.error(error("Transfer sent but no transaction hash returned."));
|
|
19300
|
+
spinner2.stop();
|
|
19301
|
+
if (!mppResult.success) {
|
|
19302
|
+
console.error(error(mppResult.error || "MPP top-up failed"));
|
|
19665
19303
|
process.exit(1);
|
|
19666
19304
|
}
|
|
19667
|
-
console.log(
|
|
19668
|
-
|
|
19669
|
-
if (
|
|
19670
|
-
|
|
19671
|
-
|
|
19672
|
-
|
|
19673
|
-
|
|
19674
|
-
|
|
19675
|
-
|
|
19676
|
-
|
|
19677
|
-
|
|
19678
|
-
|
|
19679
|
-
}
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19305
|
+
console.log(heading("Top-up Complete (MPP)"));
|
|
19306
|
+
console.log("");
|
|
19307
|
+
if (mppResult.credits?.balance)
|
|
19308
|
+
console.log(label("Balance", String(mppResult.credits.balance)));
|
|
19309
|
+
console.log(success("Credits topped up via MPP."));
|
|
19310
|
+
return;
|
|
19311
|
+
}
|
|
19312
|
+
console.log(heading("Top-up Summary"));
|
|
19313
|
+
console.log("");
|
|
19314
|
+
console.log(label("Credits", creditsAmount.toLocaleString()));
|
|
19315
|
+
console.log(label("Cost", `${tokenAmount.toFixed(6)} ${token} (~$${usdAmount.toFixed(2)})`));
|
|
19316
|
+
if (pricePerToken && pricePerToken !== 1) {
|
|
19317
|
+
console.log(label("Price", `1 ${token} = $${pricePerToken.toFixed(4)}`));
|
|
19318
|
+
}
|
|
19319
|
+
if (options.wallet) {
|
|
19320
|
+
console.log(label("From", `wallet ${options.wallet} (${options.chain || "solana"})`));
|
|
19321
|
+
} else {
|
|
19322
|
+
console.log(dim("Platform will select an agent wallet on your behalf."));
|
|
19323
|
+
}
|
|
19324
|
+
console.log("");
|
|
19325
|
+
if (!options.yes) {
|
|
19326
|
+
const ok = await promptYesNo2("Proceed? [y/N] ");
|
|
19327
|
+
if (!ok) {
|
|
19328
|
+
console.log(dim("Top-up cancelled."));
|
|
19683
19329
|
process.exit(0);
|
|
19684
19330
|
}
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
});
|
|
19695
|
-
|
|
19696
|
-
if (!verifyRes.ok) {
|
|
19697
|
-
const err = await verifyRes.json().catch(() => ({ error: "Verify failed" }));
|
|
19698
|
-
console.error(error(err.error || "Transfer sent but credit verification failed."));
|
|
19699
|
-
console.log(dim(`Tx: ${txHash}`));
|
|
19700
|
-
process.exit(1);
|
|
19701
|
-
}
|
|
19702
|
-
const verifyData = await verifyRes.json();
|
|
19331
|
+
console.log("");
|
|
19332
|
+
}
|
|
19333
|
+
const spinner = ora("Submitting top-up to platform...").start();
|
|
19334
|
+
try {
|
|
19335
|
+
const body = { credits: creditsAmount, token };
|
|
19336
|
+
if (options.chain)
|
|
19337
|
+
body.chain = options.chain;
|
|
19338
|
+
if (options.wallet)
|
|
19339
|
+
body.walletAddress = options.wallet;
|
|
19340
|
+
const res = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/credits/topup`, { method: "POST", body });
|
|
19341
|
+
spinner.stop();
|
|
19703
19342
|
console.log(heading("Top-up Complete"));
|
|
19704
19343
|
console.log("");
|
|
19705
19344
|
console.log(label("Credits", source_default.bold(creditsAmount.toLocaleString())));
|
|
19706
19345
|
console.log(label("Token", `${tokenAmount.toFixed(6)} ${token}`));
|
|
19707
19346
|
console.log(label("USD", `$${usdAmount.toFixed(2)}`));
|
|
19708
|
-
if (
|
|
19709
|
-
console.log(label("
|
|
19347
|
+
if (res.txHash)
|
|
19348
|
+
console.log(label("Tx", dim(res.txHash.slice(0, 16) + "...")));
|
|
19349
|
+
if (res.credits?.balance != null) {
|
|
19350
|
+
console.log(label("Balance", source_default.bold(Number(res.credits.balance).toLocaleString())));
|
|
19710
19351
|
}
|
|
19711
19352
|
console.log("");
|
|
19712
19353
|
console.log(success("Credits topped up."));
|
|
19713
|
-
} catch (
|
|
19354
|
+
} catch (e) {
|
|
19714
19355
|
spinner.stop();
|
|
19715
|
-
console.error(error(
|
|
19356
|
+
console.error(error(e instanceof Error ? e.message : "Top-up failed"));
|
|
19716
19357
|
process.exit(1);
|
|
19717
19358
|
}
|
|
19718
19359
|
});
|
|
@@ -19833,17 +19474,16 @@ function registerSwapCommand(program2) {
|
|
|
19833
19474
|
});
|
|
19834
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>", "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) => {
|
|
19835
19476
|
try {
|
|
19836
|
-
|
|
19837
|
-
|
|
19838
|
-
|
|
19839
|
-
|
|
19477
|
+
let auth;
|
|
19478
|
+
try {
|
|
19479
|
+
auth = requireAuth();
|
|
19480
|
+
} catch (e) {
|
|
19481
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
19840
19482
|
process.exit(1);
|
|
19841
19483
|
}
|
|
19842
|
-
const
|
|
19843
|
-
const solanaAgentWallet = allWallets.find((w) => w.chain === "solana")?.address;
|
|
19844
|
-
const wallet = opts.wallet || solanaAgentWallet || config2.wallet;
|
|
19484
|
+
const wallet = opts.wallet;
|
|
19845
19485
|
if (!wallet) {
|
|
19846
|
-
console.error(error("No Solana wallet
|
|
19486
|
+
console.error(error("No Solana wallet specified. Provide --wallet <address>."));
|
|
19847
19487
|
process.exit(1);
|
|
19848
19488
|
}
|
|
19849
19489
|
const input = resolveToken(fromToken);
|
|
@@ -19876,39 +19516,24 @@ function registerSwapCommand(program2) {
|
|
|
19876
19516
|
yes: opts.yes,
|
|
19877
19517
|
commandExample: `amiko swap send ${amountStr} ${fromToken} ${toToken}`
|
|
19878
19518
|
});
|
|
19879
|
-
const swapSpinner = ora("Executing swap via
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
19519
|
+
const swapSpinner = ora("Executing swap via platform...").start();
|
|
19520
|
+
let swapData;
|
|
19521
|
+
try {
|
|
19522
|
+
swapData = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(wallet)}/swap`, {
|
|
19523
|
+
method: "POST",
|
|
19524
|
+
body: {
|
|
19525
|
+
inputMint: input.mint,
|
|
19526
|
+
outputMint: output.mint,
|
|
19527
|
+
amount: amount2,
|
|
19528
|
+
slippageBps: parseInt(opts.slippage)
|
|
19529
|
+
}
|
|
19530
|
+
});
|
|
19883
19531
|
swapSpinner.stop();
|
|
19884
|
-
|
|
19885
|
-
process.exit(1);
|
|
19886
|
-
}
|
|
19887
|
-
const swapRes = await fetch(`${billingBase}/api/crossmint/wallets/${encodeURIComponent(wallet)}/swap`, {
|
|
19888
|
-
method: "POST",
|
|
19889
|
-
headers: {
|
|
19890
|
-
"Content-Type": "application/json",
|
|
19891
|
-
Authorization: `Bearer ${billingToken}`
|
|
19892
|
-
},
|
|
19893
|
-
body: JSON.stringify({
|
|
19894
|
-
inputMint: input.mint,
|
|
19895
|
-
outputMint: output.mint,
|
|
19896
|
-
amount: amount2,
|
|
19897
|
-
slippageBps: parseInt(opts.slippage),
|
|
19898
|
-
quoteResponse: quote
|
|
19899
|
-
})
|
|
19900
|
-
});
|
|
19901
|
-
if (!swapRes.ok) {
|
|
19532
|
+
} catch (e) {
|
|
19902
19533
|
swapSpinner.stop();
|
|
19903
|
-
|
|
19904
|
-
console.error(error(err.error || `Swap failed: ${swapRes.status}`));
|
|
19905
|
-
if (err.details) {
|
|
19906
|
-
console.error(dim(typeof err.details === "string" ? err.details : JSON.stringify(err.details)));
|
|
19907
|
-
}
|
|
19534
|
+
console.error(error(e instanceof Error ? e.message : "Swap failed"));
|
|
19908
19535
|
process.exit(1);
|
|
19909
19536
|
}
|
|
19910
|
-
const swapData = await swapRes.json();
|
|
19911
|
-
swapSpinner.stop();
|
|
19912
19537
|
console.log(success("Swap executed"));
|
|
19913
19538
|
console.log("");
|
|
19914
19539
|
if (swapData.txHash) {
|
|
@@ -19946,12 +19571,12 @@ function registerSwapCommand(program2) {
|
|
|
19946
19571
|
}
|
|
19947
19572
|
|
|
19948
19573
|
// src/commands/update.ts
|
|
19949
|
-
import { execFileSync as
|
|
19574
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
19950
19575
|
import fs from "node:fs";
|
|
19951
19576
|
import path from "node:path";
|
|
19952
19577
|
function detectPackageManager() {
|
|
19953
19578
|
try {
|
|
19954
|
-
|
|
19579
|
+
execFileSync2("bun", ["--version"], { stdio: "ignore" });
|
|
19955
19580
|
return "bun";
|
|
19956
19581
|
} catch {
|
|
19957
19582
|
return "npm";
|
|
@@ -19974,7 +19599,7 @@ function syncTwinInstall() {
|
|
|
19974
19599
|
if (!src)
|
|
19975
19600
|
return false;
|
|
19976
19601
|
fs.rmSync(DATA_CLI, { recursive: true, force: true });
|
|
19977
|
-
|
|
19602
|
+
execFileSync2("cp", ["-rL", src, DATA_CLI]);
|
|
19978
19603
|
try {
|
|
19979
19604
|
fs.unlinkSync(BIN_TARGET);
|
|
19980
19605
|
} catch {}
|
|
@@ -20006,11 +19631,11 @@ function registerUpdateCommand(program2) {
|
|
|
20006
19631
|
const spinner = ora("Installing latest version...").start();
|
|
20007
19632
|
try {
|
|
20008
19633
|
if (pm === "bun") {
|
|
20009
|
-
|
|
19634
|
+
execFileSync2("bun", ["install", "-g", `${pkg}@latest`], {
|
|
20010
19635
|
stdio: "pipe"
|
|
20011
19636
|
});
|
|
20012
19637
|
} else {
|
|
20013
|
-
|
|
19638
|
+
execFileSync2("npm", ["install", "-g", `${pkg}@latest`], {
|
|
20014
19639
|
stdio: "pipe"
|
|
20015
19640
|
});
|
|
20016
19641
|
}
|
|
@@ -20028,7 +19653,7 @@ function registerUpdateCommand(program2) {
|
|
|
20028
19653
|
}
|
|
20029
19654
|
let newVersion = "latest";
|
|
20030
19655
|
try {
|
|
20031
|
-
newVersion =
|
|
19656
|
+
newVersion = execFileSync2("amiko", ["--version"], {
|
|
20032
19657
|
encoding: "utf-8"
|
|
20033
19658
|
}).trim();
|
|
20034
19659
|
} catch {}
|
|
@@ -20048,35 +19673,6 @@ function registerUpdateCommand(program2) {
|
|
|
20048
19673
|
});
|
|
20049
19674
|
}
|
|
20050
19675
|
|
|
20051
|
-
// src/lib/balance.ts
|
|
20052
|
-
async function fetchCreditsBalance(auth) {
|
|
20053
|
-
const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
|
|
20054
|
-
if (!billingToken)
|
|
20055
|
-
return null;
|
|
20056
|
-
const base = (auth.billingBase || "https://billing.heyamiko.com").replace(/\/$/, "");
|
|
20057
|
-
try {
|
|
20058
|
-
const res = await fetch(`${base}/api/credits`, {
|
|
20059
|
-
headers: { Authorization: `Bearer ${billingToken}` }
|
|
20060
|
-
});
|
|
20061
|
-
if (!res.ok)
|
|
20062
|
-
return null;
|
|
20063
|
-
const data = await res.json();
|
|
20064
|
-
const raw = data.displayBalance ?? Number(data.credits?.balance ?? 0);
|
|
20065
|
-
return typeof raw === "number" && isFinite(raw) ? Math.round(raw) : null;
|
|
20066
|
-
} catch {
|
|
20067
|
-
return null;
|
|
20068
|
-
}
|
|
20069
|
-
}
|
|
20070
|
-
async function printBalanceRemaining(auth) {
|
|
20071
|
-
const balance = await fetchCreditsBalance(auth);
|
|
20072
|
-
if (balance == null) {
|
|
20073
|
-
console.log(dim("Balance: (could not fetch)"));
|
|
20074
|
-
return;
|
|
20075
|
-
}
|
|
20076
|
-
const usd2 = (balance / 1e4).toFixed(2);
|
|
20077
|
-
console.log(label("Balance", `${balance.toLocaleString()} credits (~$${usd2})`));
|
|
20078
|
-
}
|
|
20079
|
-
|
|
20080
19676
|
// src/lib/errors.ts
|
|
20081
19677
|
async function reportHttpError(res, label2) {
|
|
20082
19678
|
const text = await res.text().catch(() => "");
|
|
@@ -20095,7 +19691,7 @@ async function reportHttpError(res, label2) {
|
|
|
20095
19691
|
// src/commands/search.ts
|
|
20096
19692
|
var TREASURY = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
20097
19693
|
function registerSearchCommand(program2) {
|
|
20098
|
-
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("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
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 address to pay from (required)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
20099
19695
|
await requireApproval({
|
|
20100
19696
|
cost: `1 ${opts.token || "AMIKO"}`,
|
|
20101
19697
|
summary: `X/Twitter search: ${query.slice(0, 80)}${query.length > 80 ? "…" : ""}`,
|
|
@@ -20105,54 +19701,40 @@ function registerSearchCommand(program2) {
|
|
|
20105
19701
|
const spinner = ora("X Search...").start();
|
|
20106
19702
|
try {
|
|
20107
19703
|
const config2 = loadConfig();
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
if (auth.mode === "none" || !billingToken) {
|
|
20113
|
-
spinner.stop();
|
|
20114
|
-
console.error(error("Not authenticated. Check .amiko.json has valid credentials."));
|
|
20115
|
-
process.exit(1);
|
|
20116
|
-
}
|
|
20117
|
-
const allWallets = auth.agentWallets || config2.agentWallets || [];
|
|
20118
|
-
const solanaWallet = allWallets.find((w) => w.chain === "solana")?.address;
|
|
20119
|
-
const evmWallet = allWallets.find((w) => w.chain === "base" || w.chain === "evm" || w.chain === "tempo")?.address;
|
|
20120
|
-
if (!solanaWallet && !evmWallet) {
|
|
19704
|
+
let auth;
|
|
19705
|
+
try {
|
|
19706
|
+
auth = requireAuth();
|
|
19707
|
+
} catch (e) {
|
|
20121
19708
|
spinner.stop();
|
|
20122
|
-
console.error(error(
|
|
20123
|
-
console.log(dim(" Re-init your twin from the Amiko dashboard to provision wallets."));
|
|
19709
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
20124
19710
|
process.exit(1);
|
|
20125
19711
|
}
|
|
20126
|
-
const
|
|
20127
|
-
const
|
|
20128
|
-
const chain =
|
|
20129
|
-
const token = payWithSolana ? opts.token || "AMIKO" : "USDC";
|
|
19712
|
+
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
19713
|
+
const token = opts.token || "AMIKO";
|
|
19714
|
+
const chain = "solana";
|
|
20130
19715
|
const amount2 = token === "AMIKO" ? "1" : "0.01";
|
|
20131
|
-
|
|
20132
|
-
|
|
20133
|
-
method: "POST",
|
|
20134
|
-
headers: {
|
|
20135
|
-
"Content-Type": "application/json",
|
|
20136
|
-
Authorization: `Bearer ${billingToken}`
|
|
20137
|
-
},
|
|
20138
|
-
body: JSON.stringify({
|
|
20139
|
-
to: TREASURY,
|
|
20140
|
-
amount: amount2,
|
|
20141
|
-
token,
|
|
20142
|
-
chain
|
|
20143
|
-
})
|
|
20144
|
-
});
|
|
20145
|
-
if (!transferRes.ok) {
|
|
19716
|
+
const wallet = opts.wallet;
|
|
19717
|
+
if (!wallet) {
|
|
20146
19718
|
spinner.stop();
|
|
20147
|
-
|
|
20148
|
-
console.error(error(err.error || `${token} payment failed: ${transferRes.status}`));
|
|
19719
|
+
console.error(error("Provide --wallet <address> to pay from."));
|
|
20149
19720
|
process.exit(1);
|
|
20150
19721
|
}
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
19722
|
+
spinner.text = `Paying ${amount2} ${token} (${chain})...`;
|
|
19723
|
+
let txHash;
|
|
19724
|
+
try {
|
|
19725
|
+
const transferData = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(wallet)}/transfer`, {
|
|
19726
|
+
method: "POST",
|
|
19727
|
+
body: { to: TREASURY, amount: amount2, token, chain }
|
|
19728
|
+
});
|
|
19729
|
+
if (!transferData.txHash) {
|
|
19730
|
+
spinner.stop();
|
|
19731
|
+
console.error(error("Payment sent but no tx hash returned."));
|
|
19732
|
+
process.exit(1);
|
|
19733
|
+
}
|
|
19734
|
+
txHash = transferData.txHash;
|
|
19735
|
+
} catch (e) {
|
|
20154
19736
|
spinner.stop();
|
|
20155
|
-
console.error(error(
|
|
19737
|
+
console.error(error(e instanceof Error ? e.message : `${token} payment failed`));
|
|
20156
19738
|
process.exit(1);
|
|
20157
19739
|
}
|
|
20158
19740
|
spinner.text = `Paid ${amount2} ${token} — searching X...`;
|
|
@@ -20208,12 +19790,12 @@ function registerSearchCommand(program2) {
|
|
|
20208
19790
|
// src/commands/image.ts
|
|
20209
19791
|
var TREASURY2 = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
20210
19792
|
function registerImageCommand(program2) {
|
|
20211
|
-
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("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (
|
|
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 address to pay from (required)").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
|
|
20212
19794
|
await requireApproval({
|
|
20213
19795
|
cost: "5 AMIKO",
|
|
20214
|
-
summary: `Generate image: ${
|
|
19796
|
+
summary: `Generate image: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
|
|
20215
19797
|
yes: opts.yes,
|
|
20216
|
-
commandExample: `amiko image ${JSON.stringify(
|
|
19798
|
+
commandExample: `amiko image ${JSON.stringify(prompt)}`
|
|
20217
19799
|
});
|
|
20218
19800
|
const isTTY = process.stderr.isTTY;
|
|
20219
19801
|
const spinner = isTTY ? ora("Generating image...").start() : null;
|
|
@@ -20245,47 +19827,37 @@ function registerImageCommand(program2) {
|
|
|
20245
19827
|
};
|
|
20246
19828
|
try {
|
|
20247
19829
|
const config2 = loadConfig();
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
if (!billingToken) {
|
|
19830
|
+
let auth;
|
|
19831
|
+
try {
|
|
19832
|
+
auth = requireAuth();
|
|
19833
|
+
} catch (e) {
|
|
20253
19834
|
stopProgress();
|
|
20254
|
-
console.error(error(
|
|
19835
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
20255
19836
|
process.exit(1);
|
|
20256
19837
|
}
|
|
20257
|
-
const
|
|
20258
|
-
const
|
|
20259
|
-
if (!
|
|
19838
|
+
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
19839
|
+
const wallet = opts.wallet;
|
|
19840
|
+
if (!wallet) {
|
|
20260
19841
|
stopProgress();
|
|
20261
|
-
console.error(error("
|
|
19842
|
+
console.error(error("Provide --wallet <address> to pay from."));
|
|
20262
19843
|
process.exit(1);
|
|
20263
19844
|
}
|
|
20264
19845
|
setStatus("Paying 5 AMIKO...");
|
|
20265
|
-
|
|
20266
|
-
|
|
20267
|
-
|
|
20268
|
-
|
|
20269
|
-
|
|
20270
|
-
}
|
|
20271
|
-
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20276
|
-
|
|
20277
|
-
})
|
|
20278
|
-
if (!transferRes.ok) {
|
|
20279
|
-
stopProgress();
|
|
20280
|
-
const err = await transferRes.json().catch(() => ({ error: "Transfer failed" }));
|
|
20281
|
-
console.error(error(err.error || `Payment failed: ${transferRes.status}`));
|
|
20282
|
-
process.exit(1);
|
|
20283
|
-
}
|
|
20284
|
-
const transferData = await transferRes.json();
|
|
20285
|
-
const txHash = transferData.txHash;
|
|
20286
|
-
if (!txHash) {
|
|
19846
|
+
let txHash;
|
|
19847
|
+
try {
|
|
19848
|
+
const transferData = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(wallet)}/transfer`, {
|
|
19849
|
+
method: "POST",
|
|
19850
|
+
body: { to: TREASURY2, amount: "5", token: "AMIKO", chain: "solana" }
|
|
19851
|
+
});
|
|
19852
|
+
if (!transferData.txHash) {
|
|
19853
|
+
stopProgress();
|
|
19854
|
+
console.error(error("Payment sent but no tx hash returned."));
|
|
19855
|
+
process.exit(1);
|
|
19856
|
+
}
|
|
19857
|
+
txHash = transferData.txHash;
|
|
19858
|
+
} catch (e) {
|
|
20287
19859
|
stopProgress();
|
|
20288
|
-
console.error(error(
|
|
19860
|
+
console.error(error(e instanceof Error ? e.message : "Payment failed"));
|
|
20289
19861
|
process.exit(1);
|
|
20290
19862
|
}
|
|
20291
19863
|
startProgress("Generating image...");
|
|
@@ -20296,7 +19868,7 @@ function registerImageCommand(program2) {
|
|
|
20296
19868
|
"X-Payment-Tx": txHash
|
|
20297
19869
|
},
|
|
20298
19870
|
body: JSON.stringify({
|
|
20299
|
-
prompt
|
|
19871
|
+
prompt,
|
|
20300
19872
|
size: opts.size,
|
|
20301
19873
|
quality: opts.quality,
|
|
20302
19874
|
model: opts.model,
|
|
@@ -20317,7 +19889,7 @@ function registerImageCommand(program2) {
|
|
|
20317
19889
|
}
|
|
20318
19890
|
console.log(heading(`Image Generated
|
|
20319
19891
|
`));
|
|
20320
|
-
console.log(label("Prompt",
|
|
19892
|
+
console.log(label("Prompt", prompt));
|
|
20321
19893
|
console.log(label("Model", opts.model));
|
|
20322
19894
|
console.log(label("Size", opts.size));
|
|
20323
19895
|
console.log("");
|
|
@@ -20329,7 +19901,7 @@ function registerImageCommand(program2) {
|
|
|
20329
19901
|
console.log(label("Format", "base64 (inline image data)"));
|
|
20330
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`));
|
|
20331
19903
|
}
|
|
20332
|
-
if (img.revised_prompt && img.revised_prompt !==
|
|
19904
|
+
if (img.revised_prompt && img.revised_prompt !== prompt) {
|
|
20333
19905
|
console.log(label("Revised", dim(img.revised_prompt)));
|
|
20334
19906
|
}
|
|
20335
19907
|
}
|
|
@@ -20346,27 +19918,18 @@ function registerImageCommand(program2) {
|
|
|
20346
19918
|
|
|
20347
19919
|
// src/commands/amazon.ts
|
|
20348
19920
|
var TREASURY3 = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
|
|
20349
|
-
async function payAmiko(
|
|
20350
|
-
const
|
|
19921
|
+
async function payAmiko(auth, wallet, amount2) {
|
|
19922
|
+
const data = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(wallet)}/transfer`, {
|
|
20351
19923
|
method: "POST",
|
|
20352
|
-
|
|
20353
|
-
"Content-Type": "application/json",
|
|
20354
|
-
Authorization: `Bearer ${billingToken}`
|
|
20355
|
-
},
|
|
20356
|
-
body: JSON.stringify({ to: TREASURY3, amount: amount2, token: "AMIKO", chain: "solana" })
|
|
19924
|
+
body: { to: TREASURY3, amount: amount2, token: "AMIKO", chain: "solana" }
|
|
20357
19925
|
});
|
|
20358
|
-
if (!res.ok) {
|
|
20359
|
-
const err = await res.json().catch(() => ({ error: "Transfer failed" }));
|
|
20360
|
-
throw new Error(err.error || `Payment failed: ${res.status}`);
|
|
20361
|
-
}
|
|
20362
|
-
const data = await res.json();
|
|
20363
19926
|
if (!data.txHash)
|
|
20364
19927
|
throw new Error("No tx hash returned.");
|
|
20365
19928
|
return data.txHash;
|
|
20366
19929
|
}
|
|
20367
19930
|
function registerAmazonCommand(program2) {
|
|
20368
19931
|
const cmd = program2.command("amazon").description("Search and buy products on Amazon — paid with AMIKO");
|
|
20369
|
-
cmd.command("search <query>").description("Search Amazon products — 1 AMIKO").option("--limit <n>", "Number of results", "5").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
19932
|
+
cmd.command("search <query>").description("Search Amazon products — 1 AMIKO").option("--limit <n>", "Number of results", "5").option("--wallet <address>", "Solana wallet address to pay from (required)").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (query, opts) => {
|
|
20370
19933
|
await requireApproval({
|
|
20371
19934
|
cost: "1 AMIKO",
|
|
20372
19935
|
summary: `Amazon product search: ${query.slice(0, 80)}${query.length > 80 ? "…" : ""}`,
|
|
@@ -20376,24 +19939,23 @@ function registerAmazonCommand(program2) {
|
|
|
20376
19939
|
const spinner = ora("Searching Amazon...").start();
|
|
20377
19940
|
try {
|
|
20378
19941
|
const config2 = loadConfig();
|
|
20379
|
-
|
|
20380
|
-
|
|
20381
|
-
|
|
20382
|
-
|
|
20383
|
-
if (!billingToken) {
|
|
19942
|
+
let auth;
|
|
19943
|
+
try {
|
|
19944
|
+
auth = requireAuth();
|
|
19945
|
+
} catch (e) {
|
|
20384
19946
|
spinner.stop();
|
|
20385
|
-
console.error(error(
|
|
19947
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
20386
19948
|
process.exit(1);
|
|
20387
19949
|
}
|
|
20388
|
-
const
|
|
20389
|
-
const
|
|
20390
|
-
if (!
|
|
19950
|
+
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
19951
|
+
const wallet = opts.wallet;
|
|
19952
|
+
if (!wallet) {
|
|
20391
19953
|
spinner.stop();
|
|
20392
|
-
console.error(error("
|
|
19954
|
+
console.error(error("Provide --wallet <address>."));
|
|
20393
19955
|
process.exit(1);
|
|
20394
19956
|
}
|
|
20395
19957
|
spinner.text = "Paying 1 AMIKO...";
|
|
20396
|
-
const txHash = await payAmiko(
|
|
19958
|
+
const txHash = await payAmiko(auth, wallet, "1");
|
|
20397
19959
|
spinner.text = "Searching Amazon...";
|
|
20398
19960
|
const params = new URLSearchParams({
|
|
20399
19961
|
q: `site:amazon.com ${query}`
|
|
@@ -20444,7 +20006,6 @@ function registerAmazonCommand(program2) {
|
|
|
20444
20006
|
const spinner = ora("Getting quote...").start();
|
|
20445
20007
|
try {
|
|
20446
20008
|
const config2 = loadConfig();
|
|
20447
|
-
const auth = resolveAuth(config2);
|
|
20448
20009
|
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
20449
20010
|
const res = await fetch(`${mppBase2}/v1/amazon/quote`, {
|
|
20450
20011
|
method: "POST",
|
|
@@ -20513,7 +20074,7 @@ function usdToAmiko(usd2, pricePerAmiko) {
|
|
|
20513
20074
|
const amount2 = usd2 / pricePerAmiko;
|
|
20514
20075
|
return Math.ceil(amount2 * 100) / 100 + "";
|
|
20515
20076
|
}
|
|
20516
|
-
async function payAndCall(mppBase2, method, path2,
|
|
20077
|
+
async function payAndCall(mppBase2, method, path2, auth, wallet, amountOrAuto, body, onProgress, token = "AMIKO") {
|
|
20517
20078
|
let amount2 = amountOrAuto;
|
|
20518
20079
|
if (amount2 === "auto") {
|
|
20519
20080
|
onProgress?.("Fetching price...");
|
|
@@ -20538,25 +20099,11 @@ async function payAndCall(mppBase2, method, path2, billingBase, billingToken, so
|
|
|
20538
20099
|
amount2 = "1";
|
|
20539
20100
|
}
|
|
20540
20101
|
}
|
|
20541
|
-
onProgress?.(`Paying ${amount2}
|
|
20542
|
-
const
|
|
20102
|
+
onProgress?.(`Paying ${amount2} ${token}...`);
|
|
20103
|
+
const transferData = await amikoWebFetch(auth, `/api/agents/${encodeURIComponent(auth.twinId)}/wallets/${encodeURIComponent(wallet)}/transfer`, {
|
|
20543
20104
|
method: "POST",
|
|
20544
|
-
|
|
20545
|
-
|
|
20546
|
-
Authorization: `Bearer ${billingToken}`
|
|
20547
|
-
},
|
|
20548
|
-
body: JSON.stringify({
|
|
20549
|
-
to: TREASURY4,
|
|
20550
|
-
amount: amount2,
|
|
20551
|
-
token,
|
|
20552
|
-
chain: "solana"
|
|
20553
|
-
})
|
|
20554
|
-
});
|
|
20555
|
-
if (!transferRes.ok) {
|
|
20556
|
-
const err = await transferRes.json().catch(() => ({ error: "Transfer failed" }));
|
|
20557
|
-
throw new Error(err.error || `AMIKO payment failed: ${transferRes.status}`);
|
|
20558
|
-
}
|
|
20559
|
-
const transferData = await transferRes.json();
|
|
20105
|
+
body: { to: TREASURY4, amount: amount2, token, chain: "solana" }
|
|
20106
|
+
});
|
|
20560
20107
|
const txHash = transferData.txHash;
|
|
20561
20108
|
if (!txHash)
|
|
20562
20109
|
throw new Error("Payment sent but no tx hash returned.");
|
|
@@ -20574,7 +20121,7 @@ async function payAndCall(mppBase2, method, path2, billingBase, billingToken, so
|
|
|
20574
20121
|
}
|
|
20575
20122
|
function registerServicesCommand(program2) {
|
|
20576
20123
|
const svc = program2.command("service").alias("svc").description("Call any MPP service — pays with AMIKO tokens");
|
|
20577
|
-
svc.command("tts <voiceId> <text>").description("Text-to-speech — 1 AMIKO").option("--raw", "Output raw response").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (voiceId, text, opts) => {
|
|
20124
|
+
svc.command("tts <voiceId> <text>").description("Text-to-speech — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet address to pay from (required)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (voiceId, text, opts) => {
|
|
20578
20125
|
await requireApproval({
|
|
20579
20126
|
cost: "1 AMIKO",
|
|
20580
20127
|
summary: `Text-to-speech (voice ${voiceId}): "${text.slice(0, 60)}${text.length > 60 ? "…" : ""}"`,
|
|
@@ -20590,7 +20137,7 @@ function registerServicesCommand(program2) {
|
|
|
20590
20137
|
opts
|
|
20591
20138
|
});
|
|
20592
20139
|
});
|
|
20593
|
-
svc.command("stt <audioUrl>").description("Speech-to-text — 1 AMIKO").option("--raw", "Output raw response").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (audioUrl, opts) => {
|
|
20140
|
+
svc.command("stt <audioUrl>").description("Speech-to-text — 1 AMIKO").option("--raw", "Output raw response").option("--wallet <address>", "Solana wallet address to pay from (required)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (audioUrl, opts) => {
|
|
20594
20141
|
await requireApproval({
|
|
20595
20142
|
cost: "1 AMIKO",
|
|
20596
20143
|
summary: `Speech-to-text on ${audioUrl}`,
|
|
@@ -20624,7 +20171,7 @@ function registerServicesCommand(program2) {
|
|
|
20624
20171
|
console.log(JSON.stringify(data, null, 2));
|
|
20625
20172
|
}
|
|
20626
20173
|
});
|
|
20627
|
-
svc.command("chat <message>").description("AI chat — 1 AMIKO").option("--model <model>", "Model to use").option("--raw", "Output raw response").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (message, opts) => {
|
|
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 address to pay from (required)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (message, opts) => {
|
|
20628
20175
|
await requireApproval({
|
|
20629
20176
|
cost: "1 AMIKO",
|
|
20630
20177
|
summary: `AI chat${opts.model ? ` (model ${opts.model})` : ""}: "${message.slice(0, 60)}${message.length > 60 ? "…" : ""}"`,
|
|
@@ -20643,7 +20190,7 @@ function registerServicesCommand(program2) {
|
|
|
20643
20190
|
opts
|
|
20644
20191
|
});
|
|
20645
20192
|
});
|
|
20646
|
-
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("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (method, path2, bodyStr, opts) => {
|
|
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 address to pay from (required)").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (method, path2, bodyStr, opts) => {
|
|
20647
20194
|
const costLabel = opts.usdc ? `${opts.usdc} USDC` : opts.amiko ? `${opts.amiko} AMIKO` : "auto-priced AMIKO (check /v1/ list for endpoint price first)";
|
|
20648
20195
|
await requireApproval({
|
|
20649
20196
|
cost: costLabel,
|
|
@@ -20699,27 +20246,26 @@ async function callService(params) {
|
|
|
20699
20246
|
const spinner = ora(`${params.name}...`).start();
|
|
20700
20247
|
try {
|
|
20701
20248
|
const config2 = loadConfig();
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
if (!billingToken) {
|
|
20249
|
+
let auth;
|
|
20250
|
+
try {
|
|
20251
|
+
auth = requireAuth();
|
|
20252
|
+
} catch (e) {
|
|
20707
20253
|
spinner.stop();
|
|
20708
|
-
console.error(error(
|
|
20254
|
+
console.error(error(e instanceof Error ? e.message : "auth failed"));
|
|
20709
20255
|
process.exit(1);
|
|
20710
20256
|
}
|
|
20711
|
-
const
|
|
20712
|
-
const
|
|
20713
|
-
if (!
|
|
20257
|
+
const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
|
|
20258
|
+
const wallet = params.opts.wallet;
|
|
20259
|
+
if (!wallet) {
|
|
20714
20260
|
spinner.stop();
|
|
20715
|
-
console.error(error("
|
|
20261
|
+
console.error(error("Provide --wallet <address>."));
|
|
20716
20262
|
process.exit(1);
|
|
20717
20263
|
}
|
|
20718
20264
|
const token = params.usdc ? "USDC" : "AMIKO";
|
|
20719
20265
|
const amount2 = params.usdc || params.amiko || "auto";
|
|
20720
|
-
const { res, txHash, amikoSpent } = await payAndCall(mppBase2, params.method, params.path,
|
|
20266
|
+
const { res, txHash, amikoSpent } = await payAndCall(mppBase2, params.method, params.path, auth, wallet, amount2, params.body, (msg) => {
|
|
20721
20267
|
spinner.text = msg;
|
|
20722
|
-
});
|
|
20268
|
+
}, token);
|
|
20723
20269
|
spinner.stop();
|
|
20724
20270
|
if (!res.ok) {
|
|
20725
20271
|
await reportHttpError(res, params.name);
|
|
@@ -20773,35 +20319,31 @@ function resolveTwinId(args) {
|
|
|
20773
20319
|
function registerAccountsCommand(program2) {
|
|
20774
20320
|
program2.command("accounts").description("Show resolved identity (platform, user, twin, wallets)").option("--json", "Output as JSON").action(async (opts) => {
|
|
20775
20321
|
const config2 = loadConfig();
|
|
20776
|
-
const auth = resolveAuth(
|
|
20322
|
+
const auth = resolveAuth();
|
|
20777
20323
|
const data = {
|
|
20778
|
-
|
|
20324
|
+
authenticated: Boolean(auth.twinToken),
|
|
20779
20325
|
platformUrl: auth.platformUrl ?? config2.platformUrl ?? config2.siteBase,
|
|
20780
20326
|
userId: auth.userId ?? null,
|
|
20781
|
-
activeTwinId: auth.twinId ?? config2.twinId ?? null
|
|
20782
|
-
wallets: auth.agentWallets ?? [],
|
|
20783
|
-
hasTwinToken: Boolean(auth.twinToken),
|
|
20784
|
-
hasPlatformKey: Boolean(auth.platformKey)
|
|
20327
|
+
activeTwinId: auth.twinId ?? config2.twinId ?? null
|
|
20785
20328
|
};
|
|
20786
20329
|
renderOutput(data, (d) => {
|
|
20787
20330
|
console.log(heading("Amiko Account"));
|
|
20788
|
-
console.log(label("
|
|
20331
|
+
console.log(label("Authenticated", d.authenticated ? "yes" : "no"));
|
|
20789
20332
|
if (d.platformUrl)
|
|
20790
20333
|
console.log(label("Platform", d.platformUrl));
|
|
20791
20334
|
if (d.userId)
|
|
20792
20335
|
console.log(label("User ID", d.userId));
|
|
20793
20336
|
if (d.activeTwinId)
|
|
20794
20337
|
console.log(label("Active twin", d.activeTwinId));
|
|
20795
|
-
|
|
20796
|
-
if (d.mode === "none") {
|
|
20338
|
+
if (!d.authenticated) {
|
|
20797
20339
|
console.log("");
|
|
20798
|
-
console.log(error("No credentials found.
|
|
20340
|
+
console.log(error("No credentials found. Place .amiko.json with amikoTwinToken."));
|
|
20799
20341
|
}
|
|
20800
20342
|
}, { json: opts.json });
|
|
20801
20343
|
});
|
|
20802
20344
|
program2.command("info").description("Get twin info (name, description, voice, avatar)").option("--twin <idOrName>", "Target twin id or name").option("--json", "Output as JSON").action(async (opts) => {
|
|
20803
20345
|
const config2 = loadConfig();
|
|
20804
|
-
const auth = resolveAuth(
|
|
20346
|
+
const auth = resolveAuth();
|
|
20805
20347
|
let twinId;
|
|
20806
20348
|
try {
|
|
20807
20349
|
twinId = resolveTwinId({ flag: opts.twin, config: config2, auth });
|
|
@@ -20855,7 +20397,7 @@ function registerTwinCommand(program2) {
|
|
|
20855
20397
|
process.exit(1);
|
|
20856
20398
|
}
|
|
20857
20399
|
const config2 = loadConfig();
|
|
20858
|
-
const auth = resolveAuth(
|
|
20400
|
+
const auth = resolveAuth();
|
|
20859
20401
|
let twinId;
|
|
20860
20402
|
try {
|
|
20861
20403
|
twinId = resolveTwinId({ flag: opts.twin, config: config2, auth });
|
|
@@ -21008,7 +20550,7 @@ function detectMime(buffer, name) {
|
|
|
21008
20550
|
// src/commands/docs.ts
|
|
21009
20551
|
function twinFromFlag(opts) {
|
|
21010
20552
|
const config2 = loadConfig();
|
|
21011
|
-
const auth = resolveAuth(
|
|
20553
|
+
const auth = resolveAuth();
|
|
21012
20554
|
try {
|
|
21013
20555
|
return { twinId: resolveTwinId({ flag: opts.twin, config: config2, auth }), auth };
|
|
21014
20556
|
} catch (e) {
|
|
@@ -21154,7 +20696,7 @@ function registerDocsCommand(program2) {
|
|
|
21154
20696
|
// src/commands/voice.ts
|
|
21155
20697
|
function twinFromFlag2(opts) {
|
|
21156
20698
|
const config2 = loadConfig();
|
|
21157
|
-
const auth = resolveAuth(
|
|
20699
|
+
const auth = resolveAuth();
|
|
21158
20700
|
try {
|
|
21159
20701
|
return { twinId: resolveTwinId({ flag: opts.twin, config: config2, auth }), auth };
|
|
21160
20702
|
} catch (e) {
|
|
@@ -21273,7 +20815,7 @@ function registerVoiceCommand(program2) {
|
|
|
21273
20815
|
function registerAvatarCommand(program2) {
|
|
21274
20816
|
program2.command("avatar: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) => {
|
|
21275
20817
|
const config2 = loadConfig();
|
|
21276
|
-
const auth = resolveAuth(
|
|
20818
|
+
const auth = resolveAuth();
|
|
21277
20819
|
let twinId;
|
|
21278
20820
|
try {
|
|
21279
20821
|
twinId = resolveTwinId({ flag: opts.twin, config: config2, auth });
|
|
@@ -21331,7 +20873,7 @@ function registerAvatarCommand(program2) {
|
|
|
21331
20873
|
// src/commands/friends.ts
|
|
21332
20874
|
function registerFriendsCommand(program2) {
|
|
21333
20875
|
program2.command("friends").description("List friends").option("--type <user|twin>", "Filter by friend type").option("--json", "Output as JSON").action(async (opts) => {
|
|
21334
|
-
const auth = resolveAuth(
|
|
20876
|
+
const auth = resolveAuth();
|
|
21335
20877
|
const spinner = opts.json ? null : ora("Loading friends...").start();
|
|
21336
20878
|
try {
|
|
21337
20879
|
const data = await amikoWebFetch(auth, "/api/friends", { query: { type: opts.type } });
|
|
@@ -21362,7 +20904,7 @@ function registerFriendsCommand(program2) {
|
|
|
21362
20904
|
}
|
|
21363
20905
|
});
|
|
21364
20906
|
program2.command("friends: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) => {
|
|
21365
|
-
const auth = resolveAuth(
|
|
20907
|
+
const auth = resolveAuth();
|
|
21366
20908
|
const spinner = opts.json ? null : ora("Sending friend request...").start();
|
|
21367
20909
|
try {
|
|
21368
20910
|
const data = await amikoWebFetch(auth, "/api/friends", {
|
|
@@ -21382,7 +20924,7 @@ function registerFriendsCommand(program2) {
|
|
|
21382
20924
|
}
|
|
21383
20925
|
});
|
|
21384
20926
|
program2.command("friends:accept <friendshipId>").description("Accept a pending friend request").option("--json", "Output as JSON").action(async (friendshipId, opts) => {
|
|
21385
|
-
const auth = resolveAuth(
|
|
20927
|
+
const auth = resolveAuth();
|
|
21386
20928
|
const spinner = opts.json ? null : ora("Accepting...").start();
|
|
21387
20929
|
try {
|
|
21388
20930
|
const data = await amikoWebFetch(auth, `/api/friends/${friendshipId}`, { method: "PATCH", body: { action: "accept" } });
|
|
@@ -21400,7 +20942,7 @@ function registerFriendsCommand(program2) {
|
|
|
21400
20942
|
yes: opts.yes,
|
|
21401
20943
|
commandExample: `amiko friends:remove ${friendshipId}`
|
|
21402
20944
|
});
|
|
21403
|
-
const auth = resolveAuth(
|
|
20945
|
+
const auth = resolveAuth();
|
|
21404
20946
|
const spinner = opts.json ? null : ora("Removing...").start();
|
|
21405
20947
|
try {
|
|
21406
20948
|
const data = await amikoWebFetch(auth, `/api/friends/${friendshipId}`, { method: "DELETE" });
|
|
@@ -21417,7 +20959,7 @@ function registerFriendsCommand(program2) {
|
|
|
21417
20959
|
// src/commands/feed.ts
|
|
21418
20960
|
function registerFeedCommand(program2) {
|
|
21419
20961
|
program2.command("feed").description("Get feed posts").option("--type <for_you|friends>", "Feed type", "friends").option("--hashtag <tag>", "Filter by hashtag").option("--limit <n>", "Max results (default 10, max 100)").option("--cursor <id>", "Pagination cursor").option("--json", "Output as JSON").action(async (opts) => {
|
|
21420
|
-
const auth = resolveAuth(
|
|
20962
|
+
const auth = resolveAuth();
|
|
21421
20963
|
const spinner = opts.json ? null : ora("Loading feed...").start();
|
|
21422
20964
|
try {
|
|
21423
20965
|
const data = await amikoWebFetch(auth, "/api/feed", {
|
|
@@ -21458,7 +21000,7 @@ function registerFeedCommand(program2) {
|
|
|
21458
21000
|
}
|
|
21459
21001
|
});
|
|
21460
21002
|
program2.command("post: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) => {
|
|
21461
|
-
const auth = resolveAuth(
|
|
21003
|
+
const auth = resolveAuth();
|
|
21462
21004
|
const visibility = opts.visibility === "private" ? "private" : "public";
|
|
21463
21005
|
const spinner = opts.json ? null : ora("Publishing post...").start();
|
|
21464
21006
|
try {
|
|
@@ -21487,7 +21029,7 @@ function registerFeedCommand(program2) {
|
|
|
21487
21029
|
});
|
|
21488
21030
|
program2.command("post: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) => {
|
|
21489
21031
|
const config2 = loadConfig();
|
|
21490
|
-
const auth = resolveAuth(
|
|
21032
|
+
const auth = resolveAuth();
|
|
21491
21033
|
let twinId;
|
|
21492
21034
|
if (opts.twin || auth.twinId) {
|
|
21493
21035
|
try {
|
|
@@ -21525,7 +21067,7 @@ function registerFeedCommand(program2) {
|
|
|
21525
21067
|
// src/commands/composio.ts
|
|
21526
21068
|
function twinFromFlag3(opts) {
|
|
21527
21069
|
const config2 = loadConfig();
|
|
21528
|
-
const auth = resolveAuth(
|
|
21070
|
+
const auth = resolveAuth();
|
|
21529
21071
|
try {
|
|
21530
21072
|
return { twinId: resolveTwinId({ flag: opts.twin, config: config2, auth }), auth };
|
|
21531
21073
|
} catch (e) {
|