@heyamiko/amiko-cli 0.9.9-beta.7 → 0.9.9-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @heyamiko/amiko-cli (v0.9.9-beta.7)
1
+ # @heyamiko/amiko-cli (v0.9.9-beta.8)
2
2
 
3
3
  Manage wallets, credits, swaps, MPP marketplace services, and your Amiko twin (identity, documents, voice, avatar, friends, feed, Composio apps) from the terminal. Works for both human users and AI agents running on OpenClaw.
4
4
 
@@ -392,6 +392,11 @@ npm publish
392
392
 
393
393
  ## Changelog
394
394
 
395
+ ### 0.9.9-beta.8
396
+
397
+ - `friends reports request --pay` now does a **free preflight** (`POST /v1/friend-reports/preflight`) before signing the on-chain AMIKO transfer. Validates User → Friendship → consent → personality profile against amiko-web. If anything's wrong (wrong id shape, missing consent, missing profile), the CLI aborts with a targeted tip — no AMIKO is transferred. Closes a hole where every retry against a bad `--id` burned ~3 AMIKO via the irreversible X-Payment-Tx flow.
398
+ - Confirm prompt now resolves and shows the respondent's name and User.id (e.g. `Pay X AMIKO to regenerate a friend report with Matthew Graham (cmjz...) via friendship cmnlj...`) so a human can spot a wrong-person mistake before approval.
399
+
395
400
  ### 0.9.9-beta.7
396
401
 
397
402
  - `amiko friends list` table now shows the friend's `User.id` as the primary `USER ID` column (what `friends reports request`, `matches`, etc. all need) and surfaces `friendship_id` as a separate `FRIENDSHIP` column (used by `friends accept/remove`). Mirrors how amiko-web's UI separates the two ids: person actions take `actor.id`, row actions take `friendship_id`. JSON output unchanged. Fixes a 404 from `/api/internal/friend-reports/regenerate` when an agent fed the friendship row id back as `--id` for a paid report.
package/dist/index.js CHANGED
@@ -27404,6 +27404,40 @@ async function quoteFriendReport(auth) {
27404
27404
  usdAnchor: PRICE_USD
27405
27405
  };
27406
27406
  }
27407
+ async function preflightFriendReport(body) {
27408
+ const config2 = loadConfig();
27409
+ const mppBase2 = config2.apiBase.replace(/\/$/, "");
27410
+ const stripDidPrivy = (id) => id.startsWith("did:privy:") ? id.replace("did:privy:", "") : id;
27411
+ const normalizedBody = {
27412
+ ...body,
27413
+ initiator_user_id: stripDidPrivy(body.initiator_user_id),
27414
+ respondent_user_id: stripDidPrivy(body.respondent_user_id)
27415
+ };
27416
+ try {
27417
+ const res = await fetch(`${mppBase2}/v1/friend-reports/preflight`, {
27418
+ method: "POST",
27419
+ headers: { "Content-Type": "application/json" },
27420
+ body: JSON.stringify(normalizedBody)
27421
+ });
27422
+ const data = await res.json().catch(() => ({}));
27423
+ if (res.ok && data.ok === true) {
27424
+ return data;
27425
+ }
27426
+ return {
27427
+ ok: false,
27428
+ status: res.status,
27429
+ error: (typeof data.error === "string" ? data.error : null) ?? `preflight returned ${res.status}`,
27430
+ body: data
27431
+ };
27432
+ } catch (err) {
27433
+ return {
27434
+ ok: false,
27435
+ status: 0,
27436
+ error: err instanceof Error ? err.message : "preflight fetch failed",
27437
+ body: {}
27438
+ };
27439
+ }
27440
+ }
27407
27441
  async function mppFriendReportGenerate(auth, body, opts = {}) {
27408
27442
  const config2 = loadConfig();
27409
27443
  const mppBase2 = config2.apiBase.replace(/\/$/, "");
@@ -27513,10 +27547,39 @@ async function runPaidRegenerate(args) {
27513
27547
  console.error(error("Paid regenerate requires your user id. Add 'amikoUserId' to your .amiko.json (alongside amikoTwinToken/amikoTwinId)."));
27514
27548
  process.exit(1);
27515
27549
  }
27550
+ const preflightSpinner = args.json ? null : ora("Validating request (no charge)...").start();
27551
+ const preflight = await preflightFriendReport({
27552
+ report_type: args.type,
27553
+ initiator_user_id: auth.userId,
27554
+ respondent_user_id: args.id
27555
+ });
27556
+ preflightSpinner?.stop();
27557
+ if (!preflight.ok) {
27558
+ if (args.json) {
27559
+ console.log(JSON.stringify({
27560
+ ok: false,
27561
+ stage: "preflight",
27562
+ status: preflight.status,
27563
+ error: preflight.error,
27564
+ body: preflight.body
27565
+ }, null, 2));
27566
+ } else {
27567
+ console.error(error(`Preflight failed (HTTP ${preflight.status}): ${preflight.error}`));
27568
+ if (preflight.status === 404) {
27569
+ console.error(dim("Tip: did you pass a friendship_id where a User.id was expected? " + "Run 'amiko friends list --json' and use the friend.id field, not friendship_id."));
27570
+ } else if (preflight.status === 403) {
27571
+ console.error(dim("Tip: consent must already be granted by both users for this report_type. " + "Run 'amiko friends reports request --id <user> --type <type>' (without --pay), " + "wait for accept, then retry with --pay."));
27572
+ } else if (preflight.status === 422) {
27573
+ console.error(dim("Tip: at least one user is missing a personality profile. " + "Both users must have completed onboarding."));
27574
+ }
27575
+ }
27576
+ process.exit(1);
27577
+ }
27516
27578
  const quote = await quoteFriendReport(auth);
27517
27579
  const priceLine = "error" in quote ? "(price oracle down — actual amount computed at server)" : `${quote.amikoAmount} AMIKO ≈ $${quote.usdAnchor} (1 AMIKO = $${quote.amikoUsd.toFixed(4)})`;
27580
+ const respondentLabel = preflight.respondent.name ? `${preflight.respondent.name} (${preflight.respondent.id})` : preflight.respondent.id;
27518
27581
  await confirmDestructive({
27519
- action: `Pay ${priceLine} to regenerate a ${args.type} matching report with user ${args.id} (signed by your agent's wallet via amiko-web)`,
27582
+ action: `Pay ${priceLine} to regenerate a ${args.type} matching report with ${respondentLabel} via friendship ${preflight.friendship_id} (signed by your agent's wallet)`,
27520
27583
  yes: args.yes,
27521
27584
  commandExample: `amiko friends reports request --id ${args.id} --type ${args.type} --pay`
27522
27585
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.9.9-beta.7",
3
+ "version": "0.9.9-beta.8",
4
4
  "description": "Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call marketplace agents",
5
5
  "type": "module",
6
6
  "bin": {