@bnbagent/studio-cli 0.0.7 → 0.0.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.
Files changed (2) hide show
  1. package/dist/bag.js +96 -14
  2. package/package.json +2 -2
package/dist/bag.js CHANGED
@@ -6439,7 +6439,11 @@ import {
6439
6439
  } from "@bnbagent/sdk/wallets";
6440
6440
  import { auditedOp as auditedOp2 } from "@bnbagent/studio-runtime/audit";
6441
6441
  import { loadStudioToml as loadStudioToml9 } from "@bnbagent/studio-runtime/config";
6442
- import { getNetwork as getNetwork5, toRaw as toRaw2 } from "@bnbagent/studio-runtime/networks";
6442
+ import {
6443
+ BSC_TESTNET_FAUCET_URLS,
6444
+ getNetwork as getNetwork5,
6445
+ toRaw as toRaw2
6446
+ } from "@bnbagent/studio-runtime/networks";
6443
6447
  import { writePrivate } from "@bnbagent/studio-runtime/secretWrite";
6444
6448
  import {
6445
6449
  ALTANA_NETWORK_BY_STUDIO,
@@ -6495,6 +6499,23 @@ function loadContext(projectRoot) {
6495
6499
  address
6496
6500
  };
6497
6501
  }
6502
+ async function requireAltanaAdminGas(ctx) {
6503
+ let balance;
6504
+ try {
6505
+ balance = await readNativeBalanceRaw(ctx.address, ctx.networkName);
6506
+ } catch (error) {
6507
+ printErr(
6508
+ `warning: could not check Altana admin gas balance on ${ctx.networkName} (${error instanceof Error ? error.message : String(error)}); continuing and letting Altana return the authoritative result.`
6509
+ );
6510
+ return;
6511
+ }
6512
+ if (balance !== 0n) return;
6513
+ const symbol = ctx.networkName === "bsc-testnet" ? "tBNB" : "BNB";
6514
+ const funding = ctx.networkName === "bsc-testnet" ? ` Fund it and retry. Testnet faucets: ${BSC_TESTNET_FAUCET_URLS.join(", ")}` : " Fund it with BNB and retry.";
6515
+ throw new Error(
6516
+ `Altana admin wallet ${ctx.address} has 0 ${symbol} on ${ctx.networkName} and cannot pay gas for session administration.${funding}`
6517
+ );
6518
+ }
6498
6519
  function requirePassword() {
6499
6520
  const password = process.env[PASSWORD_ENV];
6500
6521
  if (!password) {
@@ -6646,6 +6667,7 @@ async function cmdSessionGrant(opts) {
6646
6667
  projectRoot
6647
6668
  },
6648
6669
  async () => {
6670
+ await requireAltanaAdminGas(ctx);
6649
6671
  await admin2.approveQuoteSignatureChecker(
6650
6672
  restored,
6651
6673
  deployedAddresses(ctx.network.chainId).commerceProxy
@@ -6690,6 +6712,7 @@ async function cmdSessionGrant(opts) {
6690
6712
  projectRoot
6691
6713
  },
6692
6714
  async (h) => {
6715
+ await requireAltanaAdminGas(ctx);
6693
6716
  if (existing !== null) {
6694
6717
  printErr(`Revoking existing Altana session ${existing.publicKey}\u2026`);
6695
6718
  await admin.revokeSession(existing.publicKey);
@@ -6779,6 +6802,7 @@ async function cmdSessionRevoke(opts) {
6779
6802
  projectRoot
6780
6803
  },
6781
6804
  async () => {
6805
+ await requireAltanaAdminGas(ctx);
6782
6806
  await admin.revokeSession(envelope.publicKey);
6783
6807
  }
6784
6808
  );
@@ -6818,6 +6842,7 @@ async function cmdSessionX402Setup(opts) {
6818
6842
  projectRoot
6819
6843
  },
6820
6844
  async () => {
6845
+ await requireAltanaAdminGas(ctx);
6821
6846
  await admin.approveX402SignatureChecker(restored);
6822
6847
  try {
6823
6848
  await admin.setPermit2Allowance(
@@ -8013,6 +8038,12 @@ async function cmdInit(nameArg, opts) {
8013
8038
  printErr(`error: ${target} already exists. Use --force to overwrite.`);
8014
8039
  return 2;
8015
8040
  }
8041
+ if (opts.destination === "platform" && opts.network === "bsc-mainnet") {
8042
+ printErr(
8043
+ "error: --destination platform cannot be combined with --network bsc-mainnet. The managed platform trial is testnet-only; use --destination self for mainnet, or select bsc-testnet."
8044
+ );
8045
+ return 2;
8046
+ }
8016
8047
  let runtime = opts.runtime;
8017
8048
  let network = opts.network;
8018
8049
  let destination = opts.destination;
@@ -9205,10 +9236,10 @@ function readWalletAddress(studioToml) {
9205
9236
  async function printFaucetHint(network, address) {
9206
9237
  printOut("");
9207
9238
  if (network === "bsc-testnet") {
9208
- const { BSC_TESTNET_FAUCET_URLS: BSC_TESTNET_FAUCET_URLS4 } = await import("@bnbagent/studio-runtime/networks");
9239
+ const { BSC_TESTNET_FAUCET_URLS: BSC_TESTNET_FAUCET_URLS5 } = await import("@bnbagent/studio-runtime/networks");
9209
9240
  printOut(`Your testnet wallet address: ${address}`);
9210
9241
  printOut("Fund it (free) from these faucets \u2014 paste the address above:");
9211
- for (const url of BSC_TESTNET_FAUCET_URLS4) {
9242
+ for (const url of BSC_TESTNET_FAUCET_URLS5) {
9212
9243
  printOut(` \xB7 ${url}`);
9213
9244
  }
9214
9245
  printOut("(Faucets are needed only for paid models / on-chain settle.");
@@ -10200,6 +10231,10 @@ function isDir4(p) {
10200
10231
  }
10201
10232
 
10202
10233
  // src/cli/_runtimeEnvKeys.ts
10234
+ var PAYMASTER_URL_ENV_KEYS = [
10235
+ "BNBAGENT_PAYMASTER_URL_BSC_MAINNET",
10236
+ "BNBAGENT_PAYMASTER_URL_BSC_TESTNET"
10237
+ ];
10203
10238
  function tableOf8(cfg, key) {
10204
10239
  const v = cfg[key];
10205
10240
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
@@ -10236,6 +10271,9 @@ function runtimeEnvKeysCore(cfg, resolvable) {
10236
10271
  if (resolvable("RPC_URL")) {
10237
10272
  keys.push("RPC_URL");
10238
10273
  }
10274
+ for (const key of PAYMASTER_URL_ENV_KEYS) {
10275
+ if (resolvable(key)) keys.push(key);
10276
+ }
10239
10277
  if (commerceRails(cfg).erc8183) {
10240
10278
  for (const key of ERC8183_ADDRESS_OVERRIDE_KEYS) {
10241
10279
  if (resolvable(key)) keys.push(key);
@@ -11408,6 +11446,29 @@ function erc8183RailChecks(cfg, env = process.env) {
11408
11446
  }
11409
11447
  return out;
11410
11448
  }
11449
+ function dockerUsesNode22OrNewer(source) {
11450
+ for (const line of source.split(/\r?\n/)) {
11451
+ const from = /^\s*FROM\s+(.+)$/i.exec(line);
11452
+ if (from === null) continue;
11453
+ const tokens = from[1].trim().split(/\s+/);
11454
+ if (tokens[0]?.startsWith("--platform=")) {
11455
+ tokens.shift();
11456
+ } else if (tokens[0] === "--platform") {
11457
+ tokens.splice(0, 2);
11458
+ }
11459
+ const image = tokens[0];
11460
+ if (!image || image.includes("${")) continue;
11461
+ const withoutDigest = image.split("@", 1)[0];
11462
+ const lastSegment = withoutDigest.slice(withoutDigest.lastIndexOf("/") + 1);
11463
+ const colon = lastSegment.lastIndexOf(":");
11464
+ if (colon <= 0 || lastSegment.slice(0, colon) !== "node") continue;
11465
+ const major = /^(\d+)(?:[.-]|$)/.exec(lastSegment.slice(colon + 1));
11466
+ if (major !== null && Number.parseInt(major[1], 10) >= 22) {
11467
+ return true;
11468
+ }
11469
+ }
11470
+ return false;
11471
+ }
11411
11472
  function x402SellerRailChecks(agentRoot2, cfg, target) {
11412
11473
  const payments = tableOf2(cfg, "payments");
11413
11474
  const rawSeller = payments.x402_seller;
@@ -11524,11 +11585,11 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
11524
11585
  const dockerfile = path25.join(agentRoot2, "Dockerfile");
11525
11586
  if (rails.x402 && isFile11(dockerfile)) {
11526
11587
  const source = fs26.readFileSync(dockerfile, "utf8");
11527
- if (!/^\s*FROM\s+node:22(?:[.-]|\s|$)/im.test(source)) {
11588
+ if (!dockerUsesNode22OrNewer(source)) {
11528
11589
  out.push({
11529
11590
  level: Level.WARNING,
11530
11591
  name: "x402_node_version",
11531
- message: "The x402/B402 seller requires Node 22, but this container Dockerfile does not use a node:22 base image.",
11592
+ message: "The x402/B402 seller requires Node >=22, but this container Dockerfile has no exact node image with a numeric major >=22.",
11532
11593
  details: { dockerfile }
11533
11594
  });
11534
11595
  }
@@ -12974,7 +13035,7 @@ import {
12974
13035
  findSubProjectRoot as findSubProjectRoot13,
12975
13036
  loadStudioToml as loadStudioToml17
12976
13037
  } from "@bnbagent/studio-runtime/config";
12977
- import { BSC_TESTNET_FAUCET_URLS } from "@bnbagent/studio-runtime/networks";
13038
+ import { BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS2 } from "@bnbagent/studio-runtime/networks";
12978
13039
 
12979
13040
  // src/cli/_deploy/checks/warning.ts
12980
13041
  import * as crypto4 from "crypto";
@@ -13447,8 +13508,8 @@ var checkPlatformFundingHint = async (_root, _target) => [
13447
13508
  {
13448
13509
  level: Level.INFO,
13449
13510
  name: "platform_funding_hint",
13450
- message: `testnet trial \u2014 keep a little tBNB for gas and testnet $U for commerce. Faucets: ${BSC_TESTNET_FAUCET_URLS.join(" \xB7 ")}`,
13451
- details: { faucets: [...BSC_TESTNET_FAUCET_URLS] }
13511
+ message: `testnet trial \u2014 keep a little tBNB for gas and testnet $U for commerce. Faucets: ${BSC_TESTNET_FAUCET_URLS2.join(" \xB7 ")}`,
13512
+ details: { faucets: [...BSC_TESTNET_FAUCET_URLS2] }
13452
13513
  }
13453
13514
  ];
13454
13515
  var criticalChecks = [
@@ -14428,7 +14489,7 @@ function walletWarning(root, secrets) {
14428
14489
  const who2 = typeof address === "string" && address ? ` (wallet ${address})` : "";
14429
14490
  warn(
14430
14491
  `
14431
- !!! session exposure (platform trial) !!!
14492
+ [expected \xB7 bounded Altana session]
14432
14493
  This project's bounded Altana session${who2} will be transmitted to the BNB Chain operator's Secrets Manager so the trial runtime can sign on testnet. The session is budget-limited, expiring, and revocable \u2014 the admin keystore and WALLET_PASSWORD never ship.
14433
14494
  If the current budget or expiry is wider than you want an operator-held key to carry, stop and grant a tighter one first:
14434
14495
  bag wallet session grant --force --budget-u <small> --expiry-days <short>
@@ -15070,6 +15131,15 @@ function agentNetworkDefault(root) {
15070
15131
  }
15071
15132
  return String(tableOf13(cfg, "network").default ?? "").toLowerCase();
15072
15133
  }
15134
+ function rejectPlatformMainnet(root) {
15135
+ if (agentNetworkDefault(root) !== "bsc-mainnet") {
15136
+ return null;
15137
+ }
15138
+ printErr(
15139
+ "error: the BNB Chain managed platform is testnet-only, but [network].default is bsc-mainnet. Deploy to your own provider or change the project to bsc-testnet. --skip-prepare, --force, and --yes cannot bypass this boundary."
15140
+ );
15141
+ return 1;
15142
+ }
15073
15143
  function agentDeployDestination(root) {
15074
15144
  const cfg = loadAgentCfg2(root);
15075
15145
  if (cfg === null) {
@@ -15483,6 +15553,10 @@ async function cmdDeploy(opts, deployArgs) {
15483
15553
  const rc = applyProjectRoot(opts.projectRoot);
15484
15554
  if (rc !== null) return rc;
15485
15555
  const root = resolveProjectRoot2(opts.projectRoot);
15556
+ if (opts.provider === "bnb") {
15557
+ const networkGate = rejectPlatformMainnet(root);
15558
+ if (networkGate !== null) return networkGate;
15559
+ }
15486
15560
  const deployments = discoverRecordedDeployments(root);
15487
15561
  const unavailable = unavailableProvidersForProject(root);
15488
15562
  const interactive = stdinIsTty();
@@ -15516,6 +15590,10 @@ async function cmdDeploy(opts, deployArgs) {
15516
15590
  printErr("cancelled: no deployment was started.");
15517
15591
  return selection.exitCode;
15518
15592
  }
15593
+ if (selection.provider === "bnb") {
15594
+ const networkGate = rejectPlatformMainnet(root);
15595
+ if (networkGate !== null) return networkGate;
15596
+ }
15519
15597
  if (!interactive && !opts.yes) {
15520
15598
  printErr(
15521
15599
  `error: non-interactive ${selection.operation} on ${selection.provider} requires --yes`
@@ -15587,6 +15665,10 @@ async function cmdAgent(opts, agentcoreArgs) {
15587
15665
  const root = resolveProjectRoot2(opts.projectRoot);
15588
15666
  const destination = opts.provider ? opts.provider === "bnb" ? "platform" : "self" : opts.to ?? opts.destination ?? agentDeployDestination(root);
15589
15667
  const packagingDestination = opts.to ?? opts.destination ?? agentDeployDestination(root);
15668
+ if (destination === "platform") {
15669
+ const networkGate = rejectPlatformMainnet(root);
15670
+ if (networkGate !== null) return networkGate;
15671
+ }
15590
15672
  const driftAgentRoot = findSubProjectRoot16("agent", root) ?? root;
15591
15673
  const driftKind = deployWalletKind(driftAgentRoot);
15592
15674
  rc = checkPackagingDrift(
@@ -16565,7 +16647,7 @@ import { pieverseKeyHash as pieverseKeyHash4 } from "@bnbagent/studio-runtime/ll
16565
16647
  import {
16566
16648
  BSC_MAINNET_MIN_BNB,
16567
16649
  BSC_MAINNET_MIN_U,
16568
- BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS2,
16650
+ BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS3,
16569
16651
  BSC_TESTNET_MIN_BNB,
16570
16652
  BSC_TESTNET_MIN_U,
16571
16653
  ERC8183_SUBMIT_GAS_RESERVE_BNB,
@@ -17555,7 +17637,7 @@ async function checkBalances(projectRoot, data, networkOverride) {
17555
17637
  const isMainnet = name === "bsc-mainnet";
17556
17638
  const minBnb = isTestnet ? BSC_TESTNET_MIN_BNB : isMainnet ? BSC_MAINNET_MIN_BNB : 0;
17557
17639
  const minBnbWei = BigInt(Math.round(minBnb * 1e6)) * 10n ** 12n;
17558
- const faucetHint = isTestnet ? ` \u2014 faucets: ${BSC_TESTNET_FAUCET_URLS2.join(", ")}` : "";
17640
+ const faucetHint = isTestnet ? ` \u2014 faucets: ${BSC_TESTNET_FAUCET_URLS3.join(", ")}` : "";
17559
17641
  const bnbRaw = await readNativeBalanceRaw(address, name);
17560
17642
  const reserve = ERC8183_SUBMIT_GAS_RESERVE_BNB;
17561
17643
  const reserveHint = ` (each on-chain action reserves \u2248 ${reserve} BNB worst-case)`;
@@ -17963,7 +18045,7 @@ import {
17963
18045
  updateServiceEndpoint as updateServiceEndpoint2
17964
18046
  } from "@bnbagent/studio-runtime/erc8004";
17965
18047
  import {
17966
- BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS3,
18048
+ BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS4,
17967
18049
  fromRaw as fromRaw4,
17968
18050
  getNetwork as getNetwork10
17969
18051
  } from "@bnbagent/studio-runtime/networks";
@@ -18127,7 +18209,7 @@ async function precheckRegisterGas(wallet, network) {
18127
18209
  if (balance >= REGISTER_MIN_BNB) {
18128
18210
  return null;
18129
18211
  }
18130
- const faucet = BSC_TESTNET_FAUCET_URLS3[0];
18212
+ const faucet = BSC_TESTNET_FAUCET_URLS4[0];
18131
18213
  return `ERC-8004 register needs gas to broadcast, but ${wallet.address} holds only ${balance} BNB on ${network} (need ~${REGISTER_MIN_BNB}). Fund a little tBNB and retry. Faucet: ${faucet}`;
18132
18214
  }
18133
18215
  function syncAgentRegistry(agentId, op) {
@@ -20760,7 +20842,7 @@ function buildProgram() {
20760
20842
  return program;
20761
20843
  }
20762
20844
  function cliVersion() {
20763
- return "0.0.6";
20845
+ return "0.0.8";
20764
20846
  }
20765
20847
 
20766
20848
  // src/cli/updateCheck.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bnbagent/studio-cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Skills-first toolkit and bag CLI for BNB Chain seller agents: ERC-8004 identity, ERC-8183 escrowed commerce, and x402 payments.",
5
5
  "keywords": [
6
6
  "bnb-chain",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@bnbagent/sdk": "0.5.0",
54
- "@bnbagent/studio-runtime": "0.0.7",
54
+ "@bnbagent/studio-runtime": "0.0.8",
55
55
  "ai": "^7.0.29",
56
56
  "archiver": "^8.0.0",
57
57
  "commander": "^15.0.0",