agentmall 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +75 -22
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -285,17 +285,37 @@ var FAILURE_MESSAGES = {
285
285
  function formatCents(cents) {
286
286
  return `$${(cents / 100).toFixed(2)}`;
287
287
  }
288
- function displayProduct(product) {
288
+ function getBudgetBasePrice(product) {
289
+ return product.listPrice ?? product.price;
290
+ }
291
+ function calculateSuggestedBudget(product, quantity = 1) {
292
+ const quantityClamped = Math.max(1, quantity);
293
+ const basePriceCents = getBudgetBasePrice(product) * quantityClamped;
294
+ const variableBufferCents = Math.round(basePriceCents * 0.15);
295
+ return basePriceCents + Math.max(variableBufferCents, 800);
296
+ }
297
+ function calculateMinimumBudget(product, quantity = 1) {
298
+ return product.price * Math.max(1, quantity);
299
+ }
300
+ function displayProduct(product, quantity = 1) {
301
+ const quantityClamped = Math.max(1, quantity);
302
+ const suggestedBudget = calculateSuggestedBudget(product, quantityClamped);
303
+ const linePrice = product.price * quantityClamped;
304
+ const lineListPrice = typeof product.listPrice === "number" ? product.listPrice * quantityClamped : void 0;
289
305
  console.log();
290
306
  console.log(` \x1B[1m${product.title}\x1B[0m`);
291
307
  console.log(` ${product.retailer} \u2014 ${product.availability}`);
292
308
  console.log();
293
- if (product.listPrice && product.discountPercent) {
309
+ if (lineListPrice && product.discountPercent) {
294
310
  console.log(
295
- ` Price: \x1B[32m${formatCents(product.price)}\x1B[0m \x1B[2m\x1B[9m${formatCents(product.listPrice)}\x1B[0m \x1B[33m-${product.discountPercent}%\x1B[0m`
311
+ ` Price: \x1B[32m${formatCents(linePrice)}\x1B[0m \x1B[2m\x1B[9m${formatCents(lineListPrice)}\x1B[0m \x1B[33m-${product.discountPercent}%\x1B[0m`
296
312
  );
297
313
  } else {
298
- console.log(` Price: \x1B[32m${formatCents(product.price)}\x1B[0m`);
314
+ console.log(` Price: \x1B[32m${formatCents(linePrice)}\x1B[0m`);
315
+ }
316
+ if (quantityClamped > 1) {
317
+ console.log(` Quantity: ${quantityClamped}`);
318
+ console.log(` Unit price: ${formatCents(product.price)}`);
299
319
  }
300
320
  if (product.variants?.length) {
301
321
  console.log();
@@ -306,13 +326,19 @@ function displayProduct(product) {
306
326
  }
307
327
  console.log();
308
328
  console.log(
309
- ` Suggested budget: \x1B[1m${formatCents(product.suggestedMaxBudget)}\x1B[0m (includes 15% buffer for tax and an $8 minimum shipping buffer)`
329
+ ` Suggested budget: \x1B[1m${formatCents(suggestedBudget)}\x1B[0m (includes 15% buffer for tax and an $8 minimum shipping buffer)`
310
330
  );
311
331
  console.log(
312
332
  ` Service fee: ${formatCents(SERVICE_FEE_CENTS)}`
313
333
  );
314
334
  console.log(
315
- ` Total charge: \x1B[1m${formatCents(product.suggestedMaxBudget + SERVICE_FEE_CENTS)}\x1B[0m USDC`
335
+ ` Total charge: \x1B[1m${formatCents(suggestedBudget + SERVICE_FEE_CENTS)}\x1B[0m USDC`
336
+ );
337
+ console.log(
338
+ ` Any unused amount from your max budget is refunded automatically after checkout.`
339
+ );
340
+ console.log(
341
+ ` The buffer covers unforeseen tax, shipping, and retailer price changes at final checkout.`
316
342
  );
317
343
  if (product.cached) {
318
344
  console.log(` \x1B[33m\u26A0 Price from cache \u2014 may not reflect current listing\x1B[0m`);
@@ -471,6 +497,20 @@ async function promptAddress() {
471
497
  country: "US"
472
498
  };
473
499
  }
500
+ async function promptQuantity() {
501
+ const value = await input({
502
+ message: "Quantity",
503
+ default: "1",
504
+ validate: (v) => {
505
+ const n = parseInt(v.trim(), 10);
506
+ if (!Number.isInteger(n) || n <= 0) {
507
+ return "Enter a whole number greater than 0";
508
+ }
509
+ return true;
510
+ }
511
+ });
512
+ return parseInt(value.trim(), 10);
513
+ }
474
514
  async function promptConfirm(message) {
475
515
  return confirm({ message });
476
516
  }
@@ -556,11 +596,15 @@ async function getBuyerToken(purchaseId) {
556
596
 
557
597
  // src/cli/index.ts
558
598
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
559
- async function runCommandCapture(command2, args2) {
599
+ async function runCommandCapture(command2, args2, envOverrides) {
560
600
  return await new Promise((resolve, reject) => {
561
601
  const child = spawn(command2, args2, {
562
602
  stdio: ["ignore", "pipe", "pipe"],
563
- shell: process.platform === "win32"
603
+ shell: process.platform === "win32",
604
+ env: {
605
+ ...process.env,
606
+ ...envOverrides
607
+ }
564
608
  });
565
609
  let stdout = "";
566
610
  let stderr = "";
@@ -630,17 +674,21 @@ function formatUsdAmount(cents) {
630
674
  }
631
675
  async function createPurchaseWithTempo(body) {
632
676
  const totalChargeCents = body.max_budget + SERVICE_FEE_CENTS;
633
- const result = await runCommandCapture("tempo", [
634
- "request",
635
- "-s",
636
- "--max-spend",
637
- formatUsdAmount(totalChargeCents),
638
- "-X",
639
- "POST",
640
- "--json",
641
- JSON.stringify(body),
642
- `${BASE_URL}/api/purchases`
643
- ]);
677
+ const result = await runCommandCapture(
678
+ "tempo",
679
+ [
680
+ "request",
681
+ "-s",
682
+ "-X",
683
+ "POST",
684
+ "--json",
685
+ JSON.stringify(body),
686
+ `${BASE_URL}/api/purchases`
687
+ ],
688
+ {
689
+ TEMPO_MAX_SPEND: formatUsdAmount(totalChargeCents)
690
+ }
691
+ );
644
692
  if (result.code !== 0) {
645
693
  const message = result.stderr.trim() || result.stdout.trim() || "Tempo request failed";
646
694
  throw new Error(message);
@@ -660,10 +708,13 @@ async function buy(urlArg) {
660
708
  const client = new AgentMall();
661
709
  console.log(" Looking up product...");
662
710
  const product = await client.products.lookup(url);
663
- displayProduct(product);
711
+ const quantity = await promptQuantity();
712
+ const suggestedMaxBudget = calculateSuggestedBudget(product, quantity);
713
+ const minimumBudget = calculateMinimumBudget(product, quantity);
714
+ displayProduct(product, quantity);
664
715
  const variantSelections = product.variants?.length ? await promptVariants(product.variants) : void 0;
665
716
  const address = await promptAddress();
666
- const maxBudget = await promptBudget(product.suggestedMaxBudget, product.price);
717
+ const maxBudget = await promptBudget(suggestedMaxBudget, minimumBudget);
667
718
  const { input: input2 } = await import("@inquirer/prompts");
668
719
  const buyerEmail = await input2({
669
720
  message: "Email for order updates",
@@ -672,7 +723,7 @@ async function buy(urlArg) {
672
723
  const body = {
673
724
  items: [{
674
725
  product_url: url,
675
- quantity: 1,
726
+ quantity,
676
727
  ...variantSelections?.length ? { variant: variantSelections } : {}
677
728
  }],
678
729
  delivery_address: address,
@@ -681,6 +732,8 @@ async function buy(urlArg) {
681
732
  };
682
733
  displayOrderSummary(body);
683
734
  console.log(` Total charge: \x1B[1m${formatCents(maxBudget + SERVICE_FEE_CENTS)}\x1B[0m USDC on Tempo`);
735
+ console.log(" Any unused amount from your max budget is refunded automatically after checkout.");
736
+ console.log(" The buffer covers unforeseen tax, shipping, and retailer price changes at final checkout.");
684
737
  console.log();
685
738
  const proceed = await promptConfirm("Place order?");
686
739
  if (!proceed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentmall",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "SDK and CLI for the AgentMall API — let AI agents buy physical products from US retailers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",