@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.
Files changed (3) hide show
  1. package/README.md +36 -23
  2. package/dist/index.js +466 -924
  3. 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: __accessProp.bind(mod, key),
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: __exportSetter.bind(all, name)
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/Method.js
3537
- var exports_Method = {};
3538
- __export(exports_Method, {
3539
- toServer: () => toServer,
3540
- toClient: () => toClient,
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
- import { createInterface } from "node:readline";
16724
- import { execFileSync } from "node:child_process";
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, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
17217
- import { homedir } from "node:os";
17218
- import { join } from "node:path";
17219
- var CONFIG_DIR = join(homedir(), ".amiko");
17220
- var CONFIG_FILE = join(CONFIG_DIR, "config.json");
17221
- var DEFAULTS = {
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
- const raw = readFileSync(CONFIG_FILE, "utf-8");
17235
- const parsed = JSON.parse(raw);
17236
- return normalizeConfig({ ...DEFAULTS, ...parsed });
17262
+ return JSON.parse(readFileSync(filePath, "utf-8"));
17237
17263
  } catch {
17238
- return { ...DEFAULTS };
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 result = tryLoadConfig(join2(dir, ".amiko.json"));
17294
- if (result)
17295
- return result;
17271
+ const parsed = tryRead(join(dir, ".amiko.json"));
17272
+ if (parsed)
17273
+ return parsed;
17296
17274
  dir = resolve(dir, "..");
17297
17275
  }
17298
- return null;
17276
+ return tryRead(OPENCLAW_FALLBACK_PATH);
17299
17277
  }
17300
- function tryLoadConfig(filePath) {
17301
- if (!existsSync2(filePath))
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(cliConfig) {
17323
- const agentConfig = loadAgentConfig();
17324
- if (agentConfig?.agentWallets?.length && !cliConfig.agentWallets?.length) {
17325
- cliConfig.agentWallets = agentConfig.agentWallets;
17326
- }
17327
- if (agentConfig?.billingBase && !cliConfig.billingBase) {
17328
- cliConfig.billingBase = agentConfig.billingBase;
17329
- }
17330
- if (agentConfig?.twinToken && !cliConfig.twinToken) {
17331
- cliConfig.twinToken = agentConfig.twinToken;
17332
- }
17333
- if (agentConfig?.twinId && !cliConfig.twinId) {
17334
- cliConfig.twinId = agentConfig.twinId;
17335
- }
17336
- if (agentConfig?.userId && !cliConfig.userId) {
17337
- cliConfig.userId = agentConfig.userId;
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 (agentConfig?.twinToken) {
17388
- return {
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 { mode: "none" };
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("View or update CLI configuration");
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(source_default.dim(`File: ${getConfigPath()}
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(" Marketplace", config.siteBase));
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(" Connected Key", config.connectedKeyPreview ? `${config.connectedKeyName || "API key"} (${config.connectedKeyPreview})` : source_default.dim("(not set)")));
17587
- console.log(label(" API Key", config.apiKey ? maskKey(config.apiKey) : source_default.dim("(not set)")));
17588
- console.log("");
17589
- if (!privyToken && !config.apiKey) {
17590
- console.log(dim("Get started:"));
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}`, { headers: authHeaders() });
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 as execFileSync2 } from "node:child_process";
18610
- import { existsSync as existsSync3 } from "node:fs";
18611
- import { homedir as homedir2 } from "node:os";
18612
- import { join as join3 } from "node:path";
18613
- var TEMPO_PATHS = [join3(homedir2(), ".tempo", "bin", "tempo"), "tempo"];
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
- execFileSync2(p, ["--version"], { stdio: "pipe", timeout: 3000 });
18398
+ execFileSync(p, ["--version"], { stdio: "pipe", timeout: 3000 });
18619
18399
  return p;
18620
18400
  } catch {
18621
18401
  continue;
18622
18402
  }
18623
- } else if (existsSync3(p)) {
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 || loadConfig().wallet;
18650
+ const depositor = opts.depositor;
18871
18651
  if (!depositor) {
18872
18652
  spinner.stop();
18873
- console.error(error("No depositor address. Provide --depositor or set wallet: amiko config set wallet <address>"));
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 || loadConfig().wallet;
18718
+ const depositor = opts.depositor;
18939
18719
  if (!depositor) {
18940
18720
  spinner.stop();
18941
- console.error(error("No depositor address. Provide --depositor or set wallet: amiko config set wallet <address>"));
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 amiko-web auth available. Run `amiko login` to link your account.");
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 and agent wallet balances").action(async () => {
19357
- const spinner = ora("Fetching balances...").start();
19358
- try {
19359
- const auth = resolveAuth(loadConfig());
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 for $1 = 10,000 credits)").option("--spend <amount>", "Spend this many units of --token and convert to credits at current price (e.g. --spend 1 --token SOL for '1 SOL worth of credits')").option("--yes", "Skip the interactive Proceed? prompt (summary still prints)").action(async (amountStr, options) => {
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
- const spinner = ora("Resolving auth...").start();
19211
+ let auth;
19499
19212
  try {
19500
- const auth = resolveAuth(loadConfig());
19501
- if (auth.mode === "none") {
19502
- spinner.stop();
19503
- console.error(error("Not authenticated. Check .amiko.json credentials."));
19504
- process.exit(1);
19505
- }
19506
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
19507
- if (!billingBase) {
19508
- spinner.stop();
19509
- console.error(error("Billing service not configured. Check billingBase in .amiko.json."));
19510
- process.exit(1);
19511
- }
19512
- const authToken = auth.platformKey || auth.twinToken || auth.privyToken;
19513
- if (!authToken) {
19514
- spinner.stop();
19515
- console.error(error("No API key or auth token. Check platformKey in .amiko.json."));
19516
- process.exit(1);
19517
- }
19518
- const authHeaders2 = {
19519
- Authorization: `Bearer ${authToken}`,
19520
- "Content-Type": "application/json"
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
- } catch {
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
- let creditsAmount;
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
- if (!mppResult.success) {
19599
- console.error(error(mppResult.error || "MPP top-up failed"));
19600
- process.exit(1);
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
- const agentWallet = auth.agentWallets?.find((w) => w.source === "agent");
19610
- const walletAddr = options.wallet || agentWallet?.address || auth.agentWallets?.[0]?.address;
19611
- const walletChain = options.chain || auth.agentWallets?.find((w) => w.address === walletAddr)?.chain || "solana";
19612
- if (!walletAddr) {
19613
- console.error(error("No wallet found. Specify --wallet <address>"));
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
- const shortWallet = walletAddr.length > 12 ? `${walletAddr.slice(0, 6)}...${walletAddr.slice(-4)}` : walletAddr;
19617
- console.log(heading("Top-up Summary"));
19618
- console.log("");
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
- const confirmed = await promptYesNo2("Proceed? [y/N] ");
19629
- if (!confirmed) {
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
- if (["base", "ethereum", "tempo"].includes(walletChain)) {
19636
- console.error(error("EVM topup not supported yet. Use a Solana wallet with --token AMIKO, USDC, USDT, or SOL."));
19637
- process.exit(1);
19638
- }
19639
- const TREASURY = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
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
- if (!transferRes.ok) {
19652
- spinner3.stop();
19653
- const err = await transferRes.json().catch(() => ({ error: "Transfer failed" }));
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(label("Tx Hash", dim(txHash.slice(0, 16) + "...")));
19668
- let keyId = auth.connectedKeyId;
19669
- if (!keyId && authToken) {
19670
- try {
19671
- const keysRes = await fetch(`${auth.billingBase || "https://billing.heyamiko.com"}/api/user/keys`, { headers: { Authorization: `Bearer ${authToken}` } });
19672
- if (keysRes.ok) {
19673
- const keysData = await keysRes.json();
19674
- const active = keysData.keys?.find((k) => k.isActive !== false);
19675
- if (active)
19676
- keyId = active.id;
19677
- }
19678
- } catch {}
19679
- }
19680
- if (!keyId) {
19681
- console.log(warn("No API key found — transfer sent but credits not verified."));
19682
- console.log(dim(`Tx: ${txHash}`));
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
- const spinner4 = ora("Verifying and crediting...").start();
19686
- const verifyRes = await fetch(`${auth.billingBase || "https://billing.heyamiko.com"}/api/user/keys/${keyId}/topup/wallet`, {
19687
- method: "POST",
19688
- headers: authHeaders2,
19689
- body: JSON.stringify({
19690
- txSignature: txHash,
19691
- amount: tokenAmount,
19692
- token: token.toUpperCase()
19693
- })
19694
- });
19695
- spinner4.stop();
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 (verifyData.credits?.balance) {
19709
- console.log(label("Balance", source_default.bold(Number(verifyData.credits.balance).toLocaleString())));
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 (err) {
19354
+ } catch (e) {
19714
19355
  spinner.stop();
19715
- console.error(error(err instanceof Error ? err.message : "Failed to top up credits"));
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
- const config2 = loadConfig();
19837
- const auth = resolveAuth(config2);
19838
- if (auth.mode === "none") {
19839
- console.error(error("Not authenticated. Check .amiko.json credentials."));
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 allWallets = auth.agentWallets || config2.agentWallets || [];
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 found. Provide --wallet <address>"));
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 Crossmint...").start();
19880
- const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
19881
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
19882
- if (!billingToken) {
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
- console.error(error("No auth token available for swap"));
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
- const err = await swapRes.json().catch(() => ({ error: "Swap failed" }));
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 execFileSync3 } from "node:child_process";
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
- execFileSync3("bun", ["--version"], { stdio: "ignore" });
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
- execFileSync3("cp", ["-rL", src, DATA_CLI]);
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
- execFileSync3("bun", ["install", "-g", `${pkg}@latest`], {
19634
+ execFileSync2("bun", ["install", "-g", `${pkg}@latest`], {
20010
19635
  stdio: "pipe"
20011
19636
  });
20012
19637
  } else {
20013
- execFileSync3("npm", ["install", "-g", `${pkg}@latest`], {
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 = execFileSync3("amiko", ["--version"], {
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
- const auth = resolveAuth(config2);
20109
- const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
20110
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
20111
- const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
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("No wallet found. Your twin needs a Solana or EVM wallet."));
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 payWithSolana = !!solanaWallet;
20127
- const wallet = payWithSolana ? solanaWallet : evmWallet;
20128
- const chain = payWithSolana ? "solana" : "base";
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
- spinner.text = `Paying ${amount2} ${token} (${chain})...`;
20132
- const transferRes = await fetch(`${billingBase}/api/crossmint/wallets/${encodeURIComponent(wallet)}/transfer`, {
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
- const err = await transferRes.json().catch(() => ({ error: "Transfer failed" }));
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
- const transferData = await transferRes.json();
20152
- const txHash = transferData.txHash;
20153
- if (!txHash) {
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("Payment sent but no tx hash returned."));
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 (prompt2, opts) => {
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: ${prompt2.slice(0, 80)}${prompt2.length > 80 ? "…" : ""}`,
19796
+ summary: `Generate image: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
20215
19797
  yes: opts.yes,
20216
- commandExample: `amiko image ${JSON.stringify(prompt2)}`
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
- const auth = resolveAuth(config2);
20249
- const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
20250
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
20251
- const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
20252
- if (!billingToken) {
19830
+ let auth;
19831
+ try {
19832
+ auth = requireAuth();
19833
+ } catch (e) {
20253
19834
  stopProgress();
20254
- console.error(error("Not authenticated. Check .amiko.json credentials."));
19835
+ console.error(error(e instanceof Error ? e.message : "auth failed"));
20255
19836
  process.exit(1);
20256
19837
  }
20257
- const allWallets = auth.agentWallets || config2.agentWallets || [];
20258
- const solanaWallet = allWallets.find((w) => w.chain === "solana")?.address;
20259
- if (!solanaWallet) {
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("No Solana wallet for AMIKO payment."));
19842
+ console.error(error("Provide --wallet <address> to pay from."));
20262
19843
  process.exit(1);
20263
19844
  }
20264
19845
  setStatus("Paying 5 AMIKO...");
20265
- const transferRes = await fetch(`${billingBase}/api/crossmint/wallets/${encodeURIComponent(solanaWallet)}/transfer`, {
20266
- method: "POST",
20267
- headers: {
20268
- "Content-Type": "application/json",
20269
- Authorization: `Bearer ${billingToken}`
20270
- },
20271
- body: JSON.stringify({
20272
- to: TREASURY2,
20273
- amount: "5",
20274
- token: "AMIKO",
20275
- chain: "solana"
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("Payment sent but no tx hash returned."));
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: prompt2,
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", prompt2));
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 !== prompt2) {
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(billingBase, billingToken, solanaWallet, amount2) {
20350
- const res = await fetch(`${billingBase}/api/crossmint/wallets/${encodeURIComponent(solanaWallet)}/transfer`, {
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
- headers: {
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
- const auth = resolveAuth(config2);
20380
- const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
20381
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
20382
- const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
20383
- if (!billingToken) {
19942
+ let auth;
19943
+ try {
19944
+ auth = requireAuth();
19945
+ } catch (e) {
20384
19946
  spinner.stop();
20385
- console.error(error("Not authenticated. Check .amiko.json credentials."));
19947
+ console.error(error(e instanceof Error ? e.message : "auth failed"));
20386
19948
  process.exit(1);
20387
19949
  }
20388
- const allWallets = auth.agentWallets || config2.agentWallets || [];
20389
- const solanaWallet = allWallets.find((w) => w.chain === "solana")?.address;
20390
- if (!solanaWallet) {
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("No Solana wallet."));
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(billingBase, billingToken, solanaWallet, "1");
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, billingBase, billingToken, solanaWallet, amountOrAuto, body, onProgress, token = "AMIKO") {
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} AMIKO...`);
20542
- const transferRes = await fetch(`${billingBase}/api/crossmint/wallets/${encodeURIComponent(solanaWallet)}/transfer`, {
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
- headers: {
20545
- "Content-Type": "application/json",
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
- const auth = resolveAuth(config2);
20703
- const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
20704
- const billingBase = auth.billingBase || "https://billing.heyamiko.com";
20705
- const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
20706
- if (!billingToken) {
20249
+ let auth;
20250
+ try {
20251
+ auth = requireAuth();
20252
+ } catch (e) {
20707
20253
  spinner.stop();
20708
- console.error(error("No auth token."));
20254
+ console.error(error(e instanceof Error ? e.message : "auth failed"));
20709
20255
  process.exit(1);
20710
20256
  }
20711
- const allWallets = auth.agentWallets || config2.agentWallets || [];
20712
- const solanaWallet = allWallets.find((w) => w.chain === "solana")?.address;
20713
- if (!solanaWallet) {
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("No Solana wallet."));
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, billingBase, billingToken, solanaWallet, token === "USDC" ? amount2 : amount2, params.body, (msg) => {
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(config2);
20322
+ const auth = resolveAuth();
20777
20323
  const data = {
20778
- mode: auth.mode,
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("Mode", d.mode));
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
- console.log(label("Wallets", String(d.wallets.length)));
20796
- if (d.mode === "none") {
20338
+ if (!d.authenticated) {
20797
20339
  console.log("");
20798
- console.log(error("No credentials found. Provision auth via .amiko.json or an API key."));
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(config2);
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(config2);
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(config2);
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(config2);
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(config2);
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(loadConfig());
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(loadConfig());
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(loadConfig());
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(loadConfig());
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(loadConfig());
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(loadConfig());
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(config2);
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(config2);
21070
+ const auth = resolveAuth();
21529
21071
  try {
21530
21072
  return { twinId: resolveTwinId({ flag: opts.twin, config: config2, auth }), auth };
21531
21073
  } catch (e) {