@bnbagent/studio-cli 0.0.6-alpha.5 → 0.0.6-alpha.7

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/dist/bag.js CHANGED
@@ -2722,6 +2722,11 @@ function client(networkName) {
2722
2722
  const net2 = getNetwork(networkName);
2723
2723
  return createPublicClient({ transport: http(net2.rpcUrl) });
2724
2724
  }
2725
+ async function readChainIdAt(rpcUrl) {
2726
+ return createPublicClient({
2727
+ transport: http(rpcUrl, { retryCount: 0, timeout: 5e3 })
2728
+ }).getChainId();
2729
+ }
2725
2730
  async function readNativeBalanceRaw(address, networkName) {
2726
2731
  return client(networkName).getBalance({
2727
2732
  address: getAddress(address)
@@ -3192,44 +3197,6 @@ function relocateKeys(src, target, label) {
3192
3197
  return true;
3193
3198
  }
3194
3199
 
3195
- // src/cli/_twakContractTargets.ts
3196
- import { resolveNetwork } from "@bnbagent/sdk";
3197
- var CONTRACT_OVERRIDES = [
3198
- ["ERC8004_REGISTRY_ADDRESS", "registryContract"],
3199
- ["ERC8183_COMMERCE_ADDRESS", "commerceContract"],
3200
- ["ERC8183_ROUTER_ADDRESS", "routerContract"],
3201
- ["ERC8183_POLICY_ADDRESS", "policyContract"]
3202
- ];
3203
- function twakCustomContractOverrides(networkName, env = process.env) {
3204
- let network;
3205
- try {
3206
- network = resolveNetwork(networkName);
3207
- } catch {
3208
- return [];
3209
- }
3210
- const erc8183 = erc8183ContractOverrideState(env);
3211
- const out = [];
3212
- for (const [envKey, field] of CONTRACT_OVERRIDES) {
3213
- if (envKey.startsWith("ERC8183_") && erc8183.mode !== "custom") {
3214
- continue;
3215
- }
3216
- const configured = env[envKey]?.trim() ?? "";
3217
- if (!/^0x[0-9a-fA-F]{40}$/u.test(configured)) {
3218
- continue;
3219
- }
3220
- const canonical = network[field];
3221
- if (configured.toLowerCase() !== canonical.toLowerCase()) {
3222
- out.push({ envKey, configured, canonical });
3223
- }
3224
- }
3225
- return out;
3226
- }
3227
- function twakUnsupportedContractOverrides(networkName, env = process.env) {
3228
- return twakCustomContractOverrides(networkName, env).filter(
3229
- (item) => item.envKey.startsWith("ERC8183_")
3230
- );
3231
- }
3232
-
3233
3200
  // src/cli/init.ts
3234
3201
  import * as fs23 from "fs";
3235
3202
  import * as os4 from "os";
@@ -3498,6 +3465,46 @@ import * as fs15 from "fs";
3498
3465
  import * as path14 from "path";
3499
3466
  import { envLocalPath as envLocalPath7 } from "@bnbagent/studio-runtime/config";
3500
3467
  import { resolveTwakHome } from "@bnbagent/studio-runtime/wallet";
3468
+
3469
+ // src/cli/_twakContractTargets.ts
3470
+ import { resolveNetwork } from "@bnbagent/sdk";
3471
+ var CONTRACT_OVERRIDES = [
3472
+ ["ERC8004_REGISTRY_ADDRESS", "registryContract"],
3473
+ ["ERC8183_COMMERCE_ADDRESS", "commerceContract"],
3474
+ ["ERC8183_ROUTER_ADDRESS", "routerContract"],
3475
+ ["ERC8183_POLICY_ADDRESS", "policyContract"]
3476
+ ];
3477
+ function twakCustomContractOverrides(networkName, env = process.env) {
3478
+ let network;
3479
+ try {
3480
+ network = resolveNetwork(networkName);
3481
+ } catch {
3482
+ return [];
3483
+ }
3484
+ const erc8183 = erc8183ContractOverrideState(env);
3485
+ const out = [];
3486
+ for (const [envKey, field] of CONTRACT_OVERRIDES) {
3487
+ if (envKey.startsWith("ERC8183_") && erc8183.mode !== "custom") {
3488
+ continue;
3489
+ }
3490
+ const configured = env[envKey]?.trim() ?? "";
3491
+ if (!/^0x[0-9a-fA-F]{40}$/u.test(configured)) {
3492
+ continue;
3493
+ }
3494
+ const canonical = network[field];
3495
+ if (configured.toLowerCase() !== canonical.toLowerCase()) {
3496
+ out.push({ envKey, configured, canonical });
3497
+ }
3498
+ }
3499
+ return out;
3500
+ }
3501
+ function twakUnsupportedContractOverrides(networkName, env = process.env) {
3502
+ return twakCustomContractOverrides(networkName, env).filter(
3503
+ (item) => item.envKey.startsWith("ERC8183_")
3504
+ );
3505
+ }
3506
+
3507
+ // src/cli/_deploy/checks/twak.ts
3501
3508
  var AGENTCORE_DESCRIPTOR = path14.join("agentcore", "agentcore.json");
3502
3509
  function isTwak(data) {
3503
3510
  return tableOf2(data, "wallet").kind === "twak";
@@ -4277,6 +4284,7 @@ import {
4277
4284
  import { getNetwork as getNetwork4 } from "@bnbagent/studio-runtime/networks";
4278
4285
  import * as pieverseRt from "@bnbagent/studio-runtime/pieverse";
4279
4286
  import {
4287
+ PieverseKeyNotFoundError,
4280
4288
  PieversePolicy,
4281
4289
  RetryPolicy,
4282
4290
  allocateWithSettleRetry,
@@ -4410,7 +4418,10 @@ function registerLlm(program) {
4410
4418
  ).option(
4411
4419
  "--network <name>",
4412
4420
  "Override [llm.pieverse].network (e.g. bsc-mainnet, bsc-testnet)."
4413
- ).option("--name <name>", "Key name (default: bnbagent-studio-default).").action(
4421
+ ).option("--name <name>", "Key name (default: bnbagent-studio-default).").option(
4422
+ "--replace",
4423
+ "Ignore any existing key and mint a fresh one, overwriting PIEVERSE_LLM_API_KEY in .studio/.env.local. Use when the key you inherited (e.g. from a shared env file) no longer exists in Pieverse. The old key is left untouched on the Pieverse side."
4424
+ ).action(
4414
4425
  act(
4415
4426
  (opts) => cmdActivate(opts)
4416
4427
  )
@@ -4619,9 +4630,20 @@ async function cmdActivate(opts) {
4619
4630
  return 2;
4620
4631
  }
4621
4632
  const pvCfg = loadPieverseConfig(cfg);
4622
- let existingHash = pvCfg.key_hash ? String(pvCfg.key_hash) : null;
4623
- const envFileValue = getEnvVar(envLocalPath9(root), PIEVERSE_ENV_KEY);
4624
- const existingEnv = envFileValue || process.env[PIEVERSE_ENV_KEY];
4633
+ const replace = opts.replace === true;
4634
+ let existingHash = !replace && pvCfg.key_hash ? String(pvCfg.key_hash) : null;
4635
+ const envFileValue = replace ? null : getEnvVar(envLocalPath9(root), PIEVERSE_ENV_KEY);
4636
+ const existingEnv = replace ? null : envFileValue || process.env[PIEVERSE_ENV_KEY];
4637
+ if (replace) {
4638
+ printOut(
4639
+ `\u2192 --replace: ignoring any existing ${PIEVERSE_ENV_KEY} and minting a fresh key\u2026`
4640
+ );
4641
+ if (process.env[PIEVERSE_ENV_KEY]) {
4642
+ printErr(
4643
+ `warning: ${PIEVERSE_ENV_KEY} is also exported in this shell. The new key goes to .studio/.env.local, which \`bag\` prefers, but \`unset ${PIEVERSE_ENV_KEY}\` to keep the two from diverging.`
4644
+ );
4645
+ }
4646
+ }
4625
4647
  if (!existingHash && existingEnv) {
4626
4648
  const derivedHash = pieverseKeyHash(existingEnv);
4627
4649
  printOut(
@@ -4630,15 +4652,24 @@ async function cmdActivate(opts) {
4630
4652
  try {
4631
4653
  await withSiweRetry(wallet, (token) => inspectKey(token, derivedHash));
4632
4654
  } catch (exc) {
4655
+ if (!(exc instanceof PieverseKeyNotFoundError)) {
4656
+ printErr(
4657
+ `error: could not verify the existing ${PIEVERSE_ENV_KEY} against Pieverse: ${errMessage(
4658
+ exc
4659
+ )}
4660
+ The existing key was kept and no new key was created. This looks like a transport or login failure rather than a missing key \u2014 retry \`bag llm activate\` once Pieverse is reachable.`
4661
+ );
4662
+ return 2;
4663
+ }
4633
4664
  const sources = [
4634
4665
  envFileValue ? `.studio/.env.local (a ${PIEVERSE_ENV_KEY}= line)` : "",
4635
4666
  process.env[PIEVERSE_ENV_KEY] ? "the shell environment" : ""
4636
4667
  ].filter(Boolean).join(" and ");
4637
4668
  printErr(
4638
- `error: ${PIEVERSE_ENV_KEY} already exists but its derived key_hash could not be verified: ${errMessage(
4669
+ `error: ${PIEVERSE_ENV_KEY} already exists but Pieverse does not know its key_hash: ${errMessage(
4639
4670
  exc
4640
4671
  )}
4641
- The existing key was kept and no new key was created. The key comes from ${sources}; \`bag\` reads both, so clear every source \u2014 remove the ${PIEVERSE_ENV_KEY}= line from .studio/.env.local AND \`unset ${PIEVERSE_ENV_KEY}\` in the shell \u2014 then re-run \`bag llm activate\` to mint a fresh key. (\`bag llm rotate\` replaces a key that is still valid in Pieverse; it cannot recover this one.)`
4672
+ The existing key was kept and no new key was created. The key comes from ${sources}. Re-run \`bag llm activate --replace\` to mint a fresh key and overwrite .studio/.env.local (then \`unset ${PIEVERSE_ENV_KEY}\` if you also exported it in this shell). (\`bag llm rotate\` replaces a key that is still valid in Pieverse; it cannot recover this one.)`
4642
4673
  );
4643
4674
  return 2;
4644
4675
  }
@@ -9858,6 +9889,57 @@ function isDir4(p) {
9858
9889
  }
9859
9890
  }
9860
9891
 
9892
+ // src/cli/_runtimeEnvKeys.ts
9893
+ function tableOf8(cfg, key) {
9894
+ const v = cfg[key];
9895
+ return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
9896
+ }
9897
+ function runtimeEnvKeysCore(cfg, resolvable) {
9898
+ const walletKind2 = tableOf8(cfg, "wallet").kind ?? "evm-local";
9899
+ let keys;
9900
+ if (walletKind2 === "twak") {
9901
+ keys = ["TWAK_WALLET_PASSWORD"];
9902
+ for (const k of ["TWAK_ACCESS_ID", "TWAK_HMAC_SECRET"]) {
9903
+ if (resolvable(k)) {
9904
+ keys.push(k);
9905
+ }
9906
+ }
9907
+ } else if (walletKind2 === "altana") {
9908
+ keys = [];
9909
+ } else {
9910
+ keys = ["WALLET_PASSWORD"];
9911
+ }
9912
+ const provider = tableOf8(cfg, "llm").provider;
9913
+ const providerKey = typeof provider === "string" ? PROVIDER_KEY_ENV[provider] : null;
9914
+ if (providerKey) {
9915
+ keys.push(providerKey);
9916
+ }
9917
+ const storageKind2 = String(
9918
+ tableOf8(cfg, "storage").kind ?? "local"
9919
+ ).toLowerCase();
9920
+ if (storageKind2 === "ipfs") {
9921
+ keys.push("STORAGE_API_URL");
9922
+ if (resolvable("STORAGE_API_KEY")) {
9923
+ keys.push("STORAGE_API_KEY");
9924
+ }
9925
+ }
9926
+ if (resolvable("RPC_URL")) {
9927
+ keys.push("RPC_URL");
9928
+ }
9929
+ if (commerceRails(cfg).erc8183) {
9930
+ for (const key of ERC8183_ADDRESS_OVERRIDE_KEYS) {
9931
+ if (resolvable(key)) keys.push(key);
9932
+ }
9933
+ }
9934
+ const runtime = String(tableOf8(cfg, "stack").runtime ?? "agentcore");
9935
+ if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
9936
+ for (const key of B402_RUNTIME_KEYS) {
9937
+ if (resolvable(key)) keys.push(key);
9938
+ }
9939
+ }
9940
+ return keys;
9941
+ }
9942
+
9861
9943
  // src/cli/dev.ts
9862
9944
  var DEFAULT_AGENT_HOST = "127.0.0.1";
9863
9945
  var AGENTCORE_BIN = "agentcore";
@@ -9944,17 +10026,17 @@ function loadAgentToml2(workspaceRoot) {
9944
10026
  return {};
9945
10027
  }
9946
10028
  }
9947
- function tableOf8(data, key) {
10029
+ function tableOf9(data, key) {
9948
10030
  const v = data[key];
9949
10031
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
9950
10032
  }
9951
10033
  function agentRuntime(workspaceRoot) {
9952
- const runtime = tableOf8(loadAgentToml2(workspaceRoot), "stack").runtime;
10034
+ const runtime = tableOf9(loadAgentToml2(workspaceRoot), "stack").runtime;
9953
10035
  return typeof runtime === "string" && runtime.trim() ? runtime.trim() : RUNTIME_AGENTCORE;
9954
10036
  }
9955
10037
  function agentFaces(workspaceRoot) {
9956
10038
  const cfg = loadAgentToml2(workspaceRoot);
9957
- return stackFaces(tableOf8(cfg, "stack"), tableOf8(cfg, "payments"));
10039
+ return stackFaces(tableOf9(cfg, "stack"), tableOf9(cfg, "payments"));
9958
10040
  }
9959
10041
  function localEntryFile(faces) {
9960
10042
  return `src/${entryStemOf(faces)}.ts`;
@@ -9969,7 +10051,7 @@ function storageKind(agentDir) {
9969
10051
  } catch {
9970
10052
  return "local";
9971
10053
  }
9972
- const kind = tableOf8(data, "storage").kind;
10054
+ const kind = tableOf9(data, "storage").kind;
9973
10055
  return typeof kind === "string" && kind.trim() ? kind.trim() : "local";
9974
10056
  }
9975
10057
  function networkNameOf(agentDir) {
@@ -9979,7 +10061,7 @@ function networkNameOf(agentDir) {
9979
10061
  } catch {
9980
10062
  return "bsc-testnet";
9981
10063
  }
9982
- const name = tableOf8(data, "network").default;
10064
+ const name = tableOf9(data, "network").default;
9983
10065
  return typeof name === "string" && name.trim() ? name.trim() : "bsc-testnet";
9984
10066
  }
9985
10067
  function walletKindOf(agentDir) {
@@ -9989,12 +10071,12 @@ function walletKindOf(agentDir) {
9989
10071
  } catch {
9990
10072
  return "evm-local";
9991
10073
  }
9992
- const kind = tableOf8(data, "wallet").kind;
10074
+ const kind = tableOf9(data, "wallet").kind;
9993
10075
  return typeof kind === "string" && kind.trim() ? kind.trim() : "evm-local";
9994
10076
  }
9995
10077
  function altanaSessionForRuntime(agentDir) {
9996
10078
  const cfg = loadStudioToml11(path23.join(agentDir, "studio.toml"));
9997
- const wallet = tableOf8(cfg, "wallet");
10079
+ const wallet = tableOf9(cfg, "wallet");
9998
10080
  const configured = String(
9999
10081
  wallet.session_file ?? ".studio/wallets/altana-session.json"
10000
10082
  );
@@ -10089,48 +10171,7 @@ function runtimeEnvKeys(agentDir) {
10089
10171
  } catch {
10090
10172
  cfg = {};
10091
10173
  }
10092
- const resolvable = (key) => Boolean(process.env[key]);
10093
- const kind = tableOf8(cfg, "wallet").kind;
10094
- let keys;
10095
- if (kind === "twak") {
10096
- keys = ["TWAK_WALLET_PASSWORD"];
10097
- for (const k of ["TWAK_ACCESS_ID", "TWAK_HMAC_SECRET"]) {
10098
- if (resolvable(k)) {
10099
- keys.push(k);
10100
- }
10101
- }
10102
- } else if (kind === "altana") {
10103
- keys = [];
10104
- } else {
10105
- keys = ["WALLET_PASSWORD"];
10106
- }
10107
- const provider = tableOf8(cfg, "llm").provider;
10108
- const providerKey = typeof provider === "string" ? PROVIDER_KEY_ENV[provider] : null;
10109
- if (providerKey) {
10110
- keys.push(providerKey);
10111
- }
10112
- const sk = String(tableOf8(cfg, "storage").kind ?? "local").toLowerCase();
10113
- if (sk === "ipfs") {
10114
- keys.push("STORAGE_API_URL");
10115
- if (resolvable("STORAGE_API_KEY")) {
10116
- keys.push("STORAGE_API_KEY");
10117
- }
10118
- }
10119
- if (resolvable("RPC_URL")) {
10120
- keys.push("RPC_URL");
10121
- }
10122
- if (commerceRails(cfg).erc8183) {
10123
- for (const key of ERC8183_ADDRESS_OVERRIDE_KEYS) {
10124
- if (resolvable(key)) keys.push(key);
10125
- }
10126
- }
10127
- const runtime = String(tableOf8(cfg, "stack").runtime ?? "agentcore");
10128
- if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
10129
- for (const key of B402_RUNTIME_KEYS) {
10130
- if (resolvable(key)) keys.push(key);
10131
- }
10132
- }
10133
- return keys;
10174
+ return runtimeEnvKeysCore(cfg, (key) => Boolean(process.env[key]));
10134
10175
  }
10135
10176
  function compactJson(text2) {
10136
10177
  try {
@@ -10142,7 +10183,7 @@ function compactJson(text2) {
10142
10183
  function readTwakFiles(agentDir) {
10143
10184
  let walletCfg = {};
10144
10185
  try {
10145
- walletCfg = tableOf8(
10186
+ walletCfg = tableOf9(
10146
10187
  loadStudioToml11(path23.join(agentDir, "studio.toml")),
10147
10188
  "wallet"
10148
10189
  );
@@ -10552,7 +10593,7 @@ function networkBanner(agentDir) {
10552
10593
  } catch {
10553
10594
  return null;
10554
10595
  }
10555
- const name = tableOf8(data, "network").default;
10596
+ const name = tableOf9(data, "network").default;
10556
10597
  if (typeof name !== "string" || !name.trim()) {
10557
10598
  return null;
10558
10599
  }
@@ -10605,49 +10646,7 @@ function runtimeEnvKeys2(agentRoot2) {
10605
10646
  cfg = {};
10606
10647
  }
10607
10648
  const resolvable = (key) => Boolean(process.env[key] || getEnvVar(envLocalPath11(agentRoot2), key));
10608
- const walletKind2 = tableOf2(cfg, "wallet").kind ?? "evm-local";
10609
- let keys;
10610
- if (walletKind2 === "twak") {
10611
- keys = ["TWAK_WALLET_PASSWORD"];
10612
- for (const k of ["TWAK_ACCESS_ID", "TWAK_HMAC_SECRET"]) {
10613
- if (resolvable(k)) {
10614
- keys.push(k);
10615
- }
10616
- }
10617
- } else if (walletKind2 === "altana") {
10618
- keys = [];
10619
- } else {
10620
- keys = ["WALLET_PASSWORD"];
10621
- }
10622
- const provider = tableOf2(cfg, "llm").provider;
10623
- const providerKey = typeof provider === "string" ? PROVIDER_KEY_ENV[provider] : null;
10624
- if (providerKey) {
10625
- keys.push(providerKey);
10626
- }
10627
- const storageKind2 = String(
10628
- tableOf2(cfg, "storage").kind ?? "local"
10629
- ).toLowerCase();
10630
- if (storageKind2 === "ipfs") {
10631
- keys.push("STORAGE_API_URL");
10632
- if (resolvable("STORAGE_API_KEY")) {
10633
- keys.push("STORAGE_API_KEY");
10634
- }
10635
- }
10636
- if (resolvable("RPC_URL")) {
10637
- keys.push("RPC_URL");
10638
- }
10639
- if (commerceRails(cfg).erc8183) {
10640
- for (const key of ERC8183_ADDRESS_OVERRIDE_KEYS) {
10641
- if (resolvable(key)) keys.push(key);
10642
- }
10643
- }
10644
- const runtime = String(tableOf2(cfg, "stack").runtime ?? "agentcore");
10645
- if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
10646
- for (const key of B402_RUNTIME_KEYS) {
10647
- if (resolvable(key)) keys.push(key);
10648
- }
10649
- }
10650
- return keys;
10649
+ return runtimeEnvKeysCore(cfg, resolvable);
10651
10650
  }
10652
10651
  var require2 = createRequire(import.meta.url);
10653
10652
  async function checkAgentcoreJsonPresent(root, target) {
@@ -11391,6 +11390,84 @@ async function checkAwsTargetsPopulated(root, target) {
11391
11390
  }
11392
11391
  ];
11393
11392
  }
11393
+ var AGENTCORE_AGENT_QUOTA_CODE = "L-F4575653";
11394
+ function awsJson(stdout) {
11395
+ try {
11396
+ const parsed = JSON.parse(stdout);
11397
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
11398
+ } catch {
11399
+ return null;
11400
+ }
11401
+ }
11402
+ async function checkAgentcoreQuotaHeadroom(root, target) {
11403
+ if (target !== "agentcore") {
11404
+ return [];
11405
+ }
11406
+ const [, region] = readAwsTarget(root);
11407
+ if (!region || !await whichBin("aws")) {
11408
+ return [];
11409
+ }
11410
+ const quotaRes = await runCapture("aws", [
11411
+ "service-quotas",
11412
+ "get-service-quota",
11413
+ "--service-code",
11414
+ "bedrock-agentcore",
11415
+ "--quota-code",
11416
+ AGENTCORE_AGENT_QUOTA_CODE,
11417
+ "--region",
11418
+ region,
11419
+ "--output",
11420
+ "json"
11421
+ ]);
11422
+ if (quotaRes.code !== 0) {
11423
+ return [];
11424
+ }
11425
+ const quota = awsJson(quotaRes.stdout)?.Quota;
11426
+ const limit = typeof quota?.Value === "number" ? quota.Value : null;
11427
+ if (limit === null) {
11428
+ return [];
11429
+ }
11430
+ const listRes = await runCapture("aws", [
11431
+ "bedrock-agentcore-control",
11432
+ "list-agent-runtimes",
11433
+ "--region",
11434
+ region,
11435
+ "--output",
11436
+ "json"
11437
+ ]);
11438
+ if (listRes.code !== 0) {
11439
+ return [];
11440
+ }
11441
+ const runtimes = awsJson(listRes.stdout)?.agentRuntimes;
11442
+ if (!Array.isArray(runtimes)) {
11443
+ return [];
11444
+ }
11445
+ const used = runtimes.length;
11446
+ const details = {
11447
+ used,
11448
+ limit,
11449
+ region,
11450
+ quota_code: AGENTCORE_AGENT_QUOTA_CODE
11451
+ };
11452
+ if (used < limit) {
11453
+ return [
11454
+ {
11455
+ level: Level.INFO,
11456
+ name: "agentcore_quota_headroom",
11457
+ message: `AgentCore runtimes: ${used}/${limit} used in ${region}.`,
11458
+ details
11459
+ }
11460
+ ];
11461
+ }
11462
+ return [
11463
+ {
11464
+ level: Level.CRITICAL,
11465
+ name: "agentcore_quota_headroom",
11466
+ message: `AgentCore runtimes: ${used}/${limit} used in ${region} \u2014 no slots left, so the deploy would fail with \`maxAgents limit exceeded\` AFTER pushing the image and creating the secret, M2M client, and execution role (all orphans). Delete a runtime you no longer need (\`bag deploy destroy\` in its workspace) or request a quota increase for ${AGENTCORE_AGENT_QUOTA_CODE} ("Total Agents per Account") in the Service Quotas console.`,
11467
+ details
11468
+ }
11469
+ ];
11470
+ }
11394
11471
  var allChecks = [
11395
11472
  checkAgentcoreJsonPresent,
11396
11473
  checkAgentcoreAuthorizerKeyLegacy,
@@ -11415,7 +11492,8 @@ var allChecks = [
11415
11492
  checkCommerceReady,
11416
11493
  checkDeployCliRunnable,
11417
11494
  checkRuntimeSecretsInjected,
11418
- checkAwsTargetsPopulated
11495
+ checkAwsTargetsPopulated,
11496
+ checkAgentcoreQuotaHeadroom
11419
11497
  ];
11420
11498
 
11421
11499
  // src/cli/_deploy/secrets.ts
@@ -11436,17 +11514,17 @@ function loadTomlOr(agentRoot2) {
11436
11514
  return {};
11437
11515
  }
11438
11516
  }
11439
- function tableOf9(cfg, key) {
11517
+ function tableOf10(cfg, key) {
11440
11518
  const v = cfg[key];
11441
11519
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
11442
11520
  }
11443
11521
  function deployWalletKind(agentRoot2) {
11444
- const kind = tableOf9(loadTomlOr(agentRoot2), "wallet").kind;
11522
+ const kind = tableOf10(loadTomlOr(agentRoot2), "wallet").kind;
11445
11523
  return kind ? String(kind) : "evm-local";
11446
11524
  }
11447
11525
  function resolveKeystoreDir3(agentRoot2) {
11448
11526
  const rel = String(
11449
- tableOf9(loadTomlOr(agentRoot2), "wallet").keystore_dir ?? ".studio/wallets"
11527
+ tableOf10(loadTomlOr(agentRoot2), "wallet").keystore_dir ?? ".studio/wallets"
11450
11528
  );
11451
11529
  return path25.resolve(path25.isAbsolute(rel) ? rel : path25.join(agentRoot2, rel));
11452
11530
  }
@@ -11461,7 +11539,7 @@ function readKeystoreJson(agentRoot2) {
11461
11539
  if (names.length === 0) {
11462
11540
  return null;
11463
11541
  }
11464
- const address = tableOf9(loadTomlOr(agentRoot2), "wallet").address;
11542
+ const address = tableOf10(loadTomlOr(agentRoot2), "wallet").address;
11465
11543
  let chosen = null;
11466
11544
  if (typeof address === "string" && address) {
11467
11545
  for (const n of names) {
@@ -11699,6 +11777,12 @@ function cognitoPackageJson() {
11699
11777
  function readme() {
11700
11778
  return `# Cognito M2M client for the AgentCore A2A inbound OAuth2 authorizer
11701
11779
 
11780
+ > **DEPRECATED.** \`bag deploy --provider aws\` now provisions its own user pool
11781
+ > and M2M client, and overwrites the values wired from this stack. Deploying
11782
+ > this app leaves a second, unused pool behind that you have to clean up
11783
+ > yourself. Keep it only if you need to own the pool out of band; otherwise run
11784
+ > \`bag deploy --provider aws\` and hand buyers the credentials it prints.
11785
+
11702
11786
  AgentCore A2A endpoints REQUIRE inbound auth (there is no anonymous mode). This
11703
11787
  seller uses **OAuth2 via Cognito** \u2014 NOT SigV4, because external buyers cannot
11704
11788
  obtain your AWS IAM credentials. Cognito has no public machine-to-machine
@@ -11739,12 +11823,11 @@ This reads the local \`cdk-outputs.json\` and patches:
11739
11823
  | \`Scope\` | \`agentcore.json\` \u2192 \`envVars[] OAUTH_SCOPE\` (+ \`.studio/.env.local\` for local dev) |
11740
11824
 
11741
11825
  \`OAUTH_TOKEN_URL\` / \`OAUTH_SCOPE\` are read by the emitted agent card from
11742
- the environment, so the published A2A agent card advertises the OAuth2 security
11743
- scheme buyers must use. They go into \`agentcore.json\` \`envVars[]\` (non-secret)
11744
- because \`.studio/.env.local\` lives outside the deploy CodeZip \u2014 so envVars[]
11745
- is the channel that actually reaches the runtime; the \`.env.local\` copy only
11746
- serves local \`bag dev\`. (\`bag deploy provision-cognito --wire <file>\` accepts a
11747
- custom outputs path.)
11826
+ the environment, so the agent card advertises the OAuth2 security scheme buyers
11827
+ must use. **A \`bag deploy\` run replaces both values (and the authorizer) with
11828
+ the pool it provisions itself**, so this wiring only takes effect for local
11829
+ \`bag dev\`. (\`bag deploy provision-cognito --wire <file>\` accepts a custom
11830
+ outputs path.)
11748
11831
 
11749
11832
  ## Issue buyer credentials
11750
11833
 
@@ -11795,7 +11878,8 @@ function wireSummary(r) {
11795
11878
  allowedClients = [${r.clientId}]
11796
11879
  - ${path26.basename(r.agentcoreJson)}: envVars[] OAUTH_TOKEN_URL + OAUTH_SCOPE (reach the runtime so the agent card advertises oauth2)
11797
11880
  - ${r.envLocal}: same pair, for local \`bag dev\`
11798
- \u2192 \`bag deploy prepare\` W9 will now pass; deploy when ready.`;
11881
+ \u2192 NOTE: a \`bag deploy\` run provisions its own pool and overwrites these
11882
+ values with the ones it issued. This wiring only feeds local \`bag dev\`.`;
11799
11883
  }
11800
11884
  function flattenCdkOutputs(raw) {
11801
11885
  const flat = {};
@@ -11823,6 +11907,49 @@ function upsertDescriptorEnvvars(cfg, values) {
11823
11907
  }
11824
11908
  }
11825
11909
  }
11910
+ function syncDescriptorOauthFacts(workspaceRoot, facts) {
11911
+ const acj = path26.join(workspaceRoot, "agentcore", "agentcore.json");
11912
+ let cfg;
11913
+ try {
11914
+ cfg = JSON.parse(fs27.readFileSync(acj, "utf-8"));
11915
+ } catch {
11916
+ return;
11917
+ }
11918
+ const envValues = {};
11919
+ if (facts.tokenUrl) {
11920
+ envValues.OAUTH_TOKEN_URL = facts.tokenUrl;
11921
+ }
11922
+ if (facts.scope) {
11923
+ envValues.OAUTH_SCOPE = facts.scope;
11924
+ }
11925
+ const authorizer = facts.discoveryUrl && facts.clientId ? {
11926
+ customJwtAuthorizer: {
11927
+ discoveryUrl: facts.discoveryUrl,
11928
+ allowedClients: [facts.clientId]
11929
+ }
11930
+ } : null;
11931
+ if (Object.keys(envValues).length === 0 && authorizer === null) {
11932
+ return;
11933
+ }
11934
+ if (Object.keys(envValues).length > 0) {
11935
+ upsertDescriptorEnvvars(cfg, envValues);
11936
+ }
11937
+ if (authorizer !== null && Array.isArray(cfg.runtimes)) {
11938
+ for (const rt of cfg.runtimes) {
11939
+ if (rt !== null && typeof rt === "object") {
11940
+ const r = rt;
11941
+ r.authorizerType = "CUSTOM_JWT";
11942
+ r.authorizerConfiguration = authorizer;
11943
+ }
11944
+ }
11945
+ }
11946
+ try {
11947
+ fs27.writeFileSync(acj, `${JSON.stringify(cfg, null, 2)}
11948
+ `, "utf-8");
11949
+ } catch {
11950
+ return;
11951
+ }
11952
+ }
11826
11953
  function upsertEnv(envLocal, values) {
11827
11954
  let lines = [];
11828
11955
  try {
@@ -12503,7 +12630,7 @@ import * as fs33 from "fs";
12503
12630
  import * as path32 from "path";
12504
12631
  import { envLocalPath as envLocalPath14 } from "@bnbagent/studio-runtime/config";
12505
12632
  import { show } from "@bnbagent/studio-runtime/erc8004";
12506
- import { getNetwork as getNetwork8 } from "@bnbagent/studio-runtime/networks";
12633
+ import { DEFAULT_RPC, getNetwork as getNetwork8 } from "@bnbagent/studio-runtime/networks";
12507
12634
  import * as walletRt3 from "@bnbagent/studio-runtime/wallet";
12508
12635
  var TBNB_MIN_WEI = 7n * 10n ** 15n;
12509
12636
  function isFile13(p) {
@@ -12665,6 +12792,51 @@ async function checkRpcUrlSetForRuntime(root, _target) {
12665
12792
  }
12666
12793
  ];
12667
12794
  }
12795
+ async function checkRuntimeRpcReachable(root, _target) {
12796
+ const netName = tableOf2(loadAgentToml(root), "network").default;
12797
+ if (!netName || typeof netName !== "string") {
12798
+ return [];
12799
+ }
12800
+ const expected = getNetwork8(netName).chainId;
12801
+ const configured = process.env.RPC_URL || getEnvVar(envLocalPath14(root), "RPC_URL") || "";
12802
+ const rpcUrl = configured || DEFAULT_RPC[netName] || "";
12803
+ if (!rpcUrl) {
12804
+ return [];
12805
+ }
12806
+ const source = configured ? "RPC_URL" : "the runtime default";
12807
+ let actual;
12808
+ try {
12809
+ actual = await readChainIdAt(rpcUrl);
12810
+ } catch (exc) {
12811
+ return [
12812
+ {
12813
+ level: Level.WARNING,
12814
+ name: "runtime_rpc_reachable",
12815
+ message: `the RPC endpoint the deployed runtime will use (${rpcUrl}, from ${source}) did not answer eth_chainId (${exc instanceof Error ? exc.message.split("\n")[0] : String(exc)}). The seller's first chain read (e.g. notify_funded verification) will fail in the cloud until a working endpoint is set.`,
12816
+ fixCmd: "bag env set RPC_URL <working-endpoint>",
12817
+ details: { rpc_url: rpcUrl, source, network: netName }
12818
+ }
12819
+ ];
12820
+ }
12821
+ if (actual !== expected) {
12822
+ return [
12823
+ {
12824
+ level: Level.WARNING,
12825
+ name: "runtime_rpc_reachable",
12826
+ message: `the RPC endpoint the deployed runtime will use (${rpcUrl}, from ${source}) answered chain_id=${actual}; expected ${expected} for ${netName}.`,
12827
+ fixCmd: "bag env set RPC_URL <endpoint-on-the-right-chain>",
12828
+ details: {
12829
+ rpc_url: rpcUrl,
12830
+ source,
12831
+ network: netName,
12832
+ expected,
12833
+ actual
12834
+ }
12835
+ }
12836
+ ];
12837
+ }
12838
+ return [];
12839
+ }
12668
12840
  async function checkInstalledRecipesUnchanged(root, _target) {
12669
12841
  const manifest = path32.join(root, ".studio", "recipes", "manifest.json");
12670
12842
  let data;
@@ -12705,59 +12877,6 @@ async function checkInstalledRecipesUnchanged(root, _target) {
12705
12877
  }
12706
12878
  return [];
12707
12879
  }
12708
- function agentcoreAuthorizer(root) {
12709
- const descriptor = path32.join(root, "agentcore", "agentcore.json");
12710
- let data;
12711
- try {
12712
- data = JSON.parse(fs33.readFileSync(descriptor, "utf-8"));
12713
- } catch {
12714
- return null;
12715
- }
12716
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
12717
- return null;
12718
- }
12719
- const runtimes = data.runtimes;
12720
- if (!Array.isArray(runtimes)) {
12721
- return null;
12722
- }
12723
- for (const rt of runtimes) {
12724
- if (rt === null || typeof rt !== "object") {
12725
- continue;
12726
- }
12727
- const auth = rt.authorizerConfiguration;
12728
- if (auth !== null && typeof auth === "object" && !Array.isArray(auth)) {
12729
- const jwt = auth.customJwtAuthorizer ?? auth.customJWTAuthorizer;
12730
- if (jwt !== null && typeof jwt === "object" && !Array.isArray(jwt)) {
12731
- return jwt;
12732
- }
12733
- }
12734
- }
12735
- return null;
12736
- }
12737
- async function checkCognitoAuthorizerConfigured(root, target) {
12738
- if (target !== "agentcore") {
12739
- return [];
12740
- }
12741
- const jwt = agentcoreAuthorizer(root);
12742
- const discovery = jwt?.discoveryUrl;
12743
- const clients = jwt?.allowedClients;
12744
- const configured = Boolean(discovery) && Array.isArray(clients) && clients.length > 0;
12745
- if (configured) {
12746
- return [];
12747
- }
12748
- return [
12749
- {
12750
- level: Level.WARNING,
12751
- name: "cognito_authorizer_configured",
12752
- message: "no Cognito authorizer configured in agentcore.json (authorizerConfiguration.customJwtAuthorizer.discoveryUrl/allowedClients) \u2192 the A2A endpoint will require SigV4/AWS creds; external buyers can't reach it. Run `bag deploy provision-cognito`, then paste the CDK outputs into the authorizer.",
12753
- fixCmd: "bag deploy provision-cognito",
12754
- details: {
12755
- discovery_url_set: Boolean(discovery),
12756
- allowed_clients: Array.isArray(clients) ? clients : []
12757
- }
12758
- }
12759
- ];
12760
- }
12761
12880
  async function checkStorageLocalNotDeployable(root, _target) {
12762
12881
  const storage = loadAgentToml(root).storage;
12763
12882
  if (storage === null || typeof storage !== "object" || Array.isArray(storage) || String(storage.kind ?? "").toLowerCase() !== "local") {
@@ -12780,14 +12899,14 @@ var allChecks4 = [
12780
12899
  checkAgentUriDataUriOrHttps,
12781
12900
  checkNetworkMatchesChainId,
12782
12901
  checkRpcUrlSetForRuntime,
12902
+ checkRuntimeRpcReachable,
12783
12903
  checkInstalledRecipesUnchanged,
12784
- checkCognitoAuthorizerConfigured,
12785
12904
  checkStorageLocalNotDeployable
12786
12905
  ];
12787
12906
 
12788
12907
  // src/cli/_deploy/checks/platform.ts
12789
12908
  var SLUG_RE = /^[a-z][a-z0-9-]{1,40}$/;
12790
- function tableOf10(data, key) {
12909
+ function tableOf11(data, key) {
12791
12910
  const value = data[key];
12792
12911
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
12793
12912
  }
@@ -12802,16 +12921,16 @@ function loadAgent(root) {
12802
12921
  }
12803
12922
  }
12804
12923
  function platformArtifact(data) {
12805
- const walletKind2 = String(tableOf10(data, "wallet").kind ?? "evm-local").trim().toLowerCase();
12924
+ const walletKind2 = String(tableOf11(data, "wallet").kind ?? "evm-local").trim().toLowerCase();
12806
12925
  if (walletKind2 === "twak") return "container";
12807
- const deploy = tableOf10(data, "deploy");
12926
+ const deploy = tableOf11(data, "deploy");
12808
12927
  const explicit = String(deploy.platform_artifact ?? "").toLowerCase();
12809
12928
  if (explicit) return explicit;
12810
12929
  return String(deploy.packaging ?? "").toLowerCase() === "container" ? "container" : "zip";
12811
12930
  }
12812
12931
  var checkPlatformEntrypointPresent = async (root, _target) => {
12813
12932
  const data = loadAgent(root);
12814
- const faces = stackFaces(tableOf10(data, "stack"), tableOf10(data, "payments"));
12933
+ const faces = stackFaces(tableOf11(data, "stack"), tableOf11(data, "payments"));
12815
12934
  const stem2 = entryStemOf(faces);
12816
12935
  const filenames = [`${stem2}.ts`];
12817
12936
  if (stem2 === "dualMain") filenames.push("mcpMain.ts");
@@ -12831,7 +12950,7 @@ var checkPlatformEntrypointPresent = async (root, _target) => {
12831
12950
  };
12832
12951
  var checkPlatformKeystoreNotInArtifact = async (root, _target) => {
12833
12952
  const data = loadAgent(root);
12834
- const wallet = tableOf10(data, "wallet");
12953
+ const wallet = tableOf11(data, "wallet");
12835
12954
  if (String(wallet.kind ?? "evm-local") === "twak") return [];
12836
12955
  const agent = path33.resolve(agentRoot(root));
12837
12956
  const configured = String(wallet.keystore_dir ?? ".studio/wallets");
@@ -12855,7 +12974,7 @@ var checkPlatformKeystoreNotInArtifact = async (root, _target) => {
12855
12974
  ];
12856
12975
  };
12857
12976
  var checkPlatformTestnetOnly = async (root, _target) => {
12858
- const network = String(tableOf10(loadAgent(root), "network").default ?? "").trim().toLowerCase();
12977
+ const network = String(tableOf11(loadAgent(root), "network").default ?? "").trim().toLowerCase();
12859
12978
  if (!network || network === "bsc-testnet") return [];
12860
12979
  return [
12861
12980
  {
@@ -12868,7 +12987,7 @@ var checkPlatformTestnetOnly = async (root, _target) => {
12868
12987
  ];
12869
12988
  };
12870
12989
  var checkPlatformSlugValid = async (root, _target) => {
12871
- const platform = tableOf10(tableOf10(loadAgent(root), "deploy"), "platform");
12990
+ const platform = tableOf11(tableOf11(loadAgent(root), "deploy"), "platform");
12872
12991
  const slug = String(platform.slug ?? "").trim();
12873
12992
  if (!slug || SLUG_RE.test(slug)) return [];
12874
12993
  return [
@@ -12926,7 +13045,7 @@ var checkPlatformStorageEndpoint = async (root, _target) => {
12926
13045
  };
12927
13046
  var checkPlatformMcpSyncTimeout = async (root, _target) => {
12928
13047
  const data = loadAgent(root);
12929
- const faces = stackFaces(tableOf10(data, "stack"), tableOf10(data, "payments"));
13048
+ const faces = stackFaces(tableOf11(data, "stack"), tableOf11(data, "payments"));
12930
13049
  if (!hasMcpFace(faces)) return [];
12931
13050
  const dual = hasA2aFace(faces);
12932
13051
  return [
@@ -12939,8 +13058,8 @@ var checkPlatformMcpSyncTimeout = async (root, _target) => {
12939
13058
  ];
12940
13059
  };
12941
13060
  var checkPlatformX402MerchantsMainnet = async (root, _target) => {
12942
- const merchants = tableOf10(
12943
- tableOf10(tableOf10(loadAgent(root), "payments"), "x402"),
13061
+ const merchants = tableOf11(
13062
+ tableOf11(tableOf11(loadAgent(root), "payments"), "x402"),
12944
13063
  "merchants"
12945
13064
  );
12946
13065
  const names = Object.keys(merchants).sort();
@@ -13001,7 +13120,8 @@ var warningChecks = [
13001
13120
  checkPlatformX402MerchantsMainnet,
13002
13121
  checkWalletBalancesAllZero,
13003
13122
  checkWalletTbnbBalanceSufficient,
13004
- checkWalletUBalanceNonzero
13123
+ checkWalletUBalanceNonzero,
13124
+ checkRuntimeRpcReachable
13005
13125
  ];
13006
13126
  var infoChecks = [
13007
13127
  checkPlatformTrialStatus,
@@ -13234,6 +13354,7 @@ function baseResult(endpoint, runtime, overrides) {
13234
13354
  studioTomlUpdated: false,
13235
13355
  runtime,
13236
13356
  note: null,
13357
+ warning: null,
13237
13358
  error: null,
13238
13359
  exitCode: 0,
13239
13360
  ...overrides
@@ -13273,15 +13394,15 @@ async function runVerify(opts) {
13273
13394
  exitCode: 1
13274
13395
  });
13275
13396
  }
13276
- const tableOf16 = (key) => {
13397
+ const tableOf17 = (key) => {
13277
13398
  const v = data[key];
13278
13399
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
13279
13400
  };
13280
- const network = opts.network || String(tableOf16("network").default ?? "bsc-testnet");
13401
+ const network = opts.network || String(tableOf17("network").default ?? "bsc-testnet");
13281
13402
  const protocol = nativeProtocolOf(
13282
- stackFaces(tableOf16("stack"), tableOf16("payments"))
13403
+ stackFaces(tableOf17("stack"), tableOf17("payments"))
13283
13404
  );
13284
- const identity = tableOf16("identity");
13405
+ const identity = tableOf17("identity");
13285
13406
  const existingAgentId = identity.agent_id;
13286
13407
  const accessDescription = accessSummaryForAgentcore(root, { protocol });
13287
13408
  let agentId = null;
@@ -13289,6 +13410,7 @@ async function runVerify(opts) {
13289
13410
  let action = "none";
13290
13411
  let registerError = null;
13291
13412
  let postWriteError = null;
13413
+ let postWriteWarning = null;
13292
13414
  let registerNote = null;
13293
13415
  let identityPendingReason = null;
13294
13416
  let registerExitCode = 0;
@@ -13321,9 +13443,8 @@ async function runVerify(opts) {
13321
13443
  const cause = e.cause !== null && typeof e.cause === "object" ? e.cause : null;
13322
13444
  const relayTxHash = typeof cause?.txHash === "string" ? cause.txHash : e.txHash;
13323
13445
  action = "register_partial";
13324
- postWriteError = relayTxHash ? `ERC-8004 register created agent_id=${e.agentId}, but setAgentURI relay tx_hash=${relayTxHash} was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.` : `ERC-8004 register created agent_id=${e.agentId}, but the setAgentURI relay submission was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.`;
13446
+ postWriteWarning = relayTxHash ? `ERC-8004 register created agent_id=${e.agentId}, but setAgentURI relay tx_hash=${relayTxHash} was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.` : `ERC-8004 register created agent_id=${e.agentId}, but the setAgentURI relay submission was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.`;
13325
13447
  identityPendingReason = "setAgentURI relay submission unverified; run bag erc8004 clear-pending before retrying";
13326
- registerExitCode = 1;
13327
13448
  } else if (e.txHash) {
13328
13449
  action = "register_pending";
13329
13450
  registerNote = `ERC-8004 register created agent_id=${e.agentId}; setAgentURI tx pending (${e.txHash}). Check the tx before retrying \`bag erc8004 update-endpoint\`.`;
@@ -13417,6 +13538,7 @@ async function runVerify(opts) {
13417
13538
  action,
13418
13539
  studioTomlUpdated,
13419
13540
  note: notes.length > 0 ? notes.join(" | ") : null,
13541
+ warning: postWriteWarning,
13420
13542
  error: postWriteError,
13421
13543
  exitCode: registerExitCode
13422
13544
  });
@@ -13436,10 +13558,16 @@ var WALLET_SECTION = "wallet";
13436
13558
  var KEYSTORE_JSON_ENV2 = "WALLET_KEYSTORE_JSON";
13437
13559
  var TWAK_WALLET_JSON_ENV2 = "TWAK_WALLET_JSON";
13438
13560
  var WALLET_MATERIAL_KEYS = [KEYSTORE_JSON_ENV2, TWAK_WALLET_JSON_ENV2];
13561
+ var RETIRED_AGENT_STATES = /* @__PURE__ */ new Set([
13562
+ "deleted",
13563
+ "retired",
13564
+ "removed",
13565
+ "reclaiming"
13566
+ ]);
13439
13567
  function isJsonObject(value) {
13440
13568
  return value !== null && typeof value === "object" && !Array.isArray(value);
13441
13569
  }
13442
- function tableOf11(cfg, key) {
13570
+ function tableOf12(cfg, key) {
13443
13571
  const value = cfg[key];
13444
13572
  return isJsonObject(value) ? value : {};
13445
13573
  }
@@ -13474,7 +13602,7 @@ function loadAgentCfg(root) {
13474
13602
  }
13475
13603
  }
13476
13604
  function platformCfg(root) {
13477
- return tableOf11(tableOf11(loadAgentCfg(root), "deploy"), "platform");
13605
+ return tableOf12(tableOf12(loadAgentCfg(root), "deploy"), "platform");
13478
13606
  }
13479
13607
  function patchTomlKv2(tomlPath, section, key, value) {
13480
13608
  let text2 = fs36.readFileSync(tomlPath, "utf-8");
@@ -13494,6 +13622,32 @@ function recordPlatformKv(root, key, value) {
13494
13622
  } catch {
13495
13623
  }
13496
13624
  }
13625
+ function retiredAgentReason(agent) {
13626
+ const candidates = [agent];
13627
+ for (const key of ["agent", "data"]) {
13628
+ const nested = agent[key];
13629
+ if (isJsonObject(nested)) {
13630
+ candidates.push(nested);
13631
+ }
13632
+ }
13633
+ for (const item of candidates) {
13634
+ for (const key of [
13635
+ "state",
13636
+ "status",
13637
+ "lifecycle_state",
13638
+ "lifecycleState"
13639
+ ]) {
13640
+ const value = item[key];
13641
+ if (typeof value === "string" && RETIRED_AGENT_STATES.has(value.toLowerCase())) {
13642
+ return value.toLowerCase();
13643
+ }
13644
+ }
13645
+ if (item.deleted_at || item.deletedAt) {
13646
+ return "deleted";
13647
+ }
13648
+ }
13649
+ return null;
13650
+ }
13497
13651
  function suggestNextSlug(slug) {
13498
13652
  const m = /(\d+)$/.exec(slug);
13499
13653
  let next;
@@ -13504,12 +13658,45 @@ function suggestNextSlug(slug) {
13504
13658
  }
13505
13659
  return next.slice(0, 41);
13506
13660
  }
13661
+ async function retiredSlugPreflight(slug, platformCmd) {
13662
+ let res;
13663
+ try {
13664
+ res = await platformCmd(["list"], {
13665
+ slug: "studio-platform",
13666
+ json: true,
13667
+ quiet: true
13668
+ });
13669
+ } catch {
13670
+ return null;
13671
+ }
13672
+ if (res.code !== 0 || !isJsonObject(res.data)) {
13673
+ return null;
13674
+ }
13675
+ const candidates = [res.data];
13676
+ for (const key of ["agents", "data", "items", "records"]) {
13677
+ const nested = res.data[key];
13678
+ if (Array.isArray(nested)) {
13679
+ candidates.push(...nested);
13680
+ }
13681
+ }
13682
+ for (const entry of candidates) {
13683
+ if (!isJsonObject(entry)) {
13684
+ continue;
13685
+ }
13686
+ const entrySlug = String(entry.slug ?? entry.name ?? "").toLowerCase();
13687
+ if (entrySlug !== slug.toLowerCase()) {
13688
+ continue;
13689
+ }
13690
+ return retiredAgentReason(entry);
13691
+ }
13692
+ return null;
13693
+ }
13507
13694
  function clearIdentityEndpointIfMatches(root, oldUrl) {
13508
13695
  if (!oldUrl) {
13509
13696
  return;
13510
13697
  }
13511
13698
  const cfg = loadAgentCfg(root);
13512
- if (String(tableOf11(cfg, "identity").endpoint ?? "") !== String(oldUrl)) {
13699
+ if (String(tableOf12(cfg, "identity").endpoint ?? "") !== String(oldUrl)) {
13513
13700
  return;
13514
13701
  }
13515
13702
  const tomlPath = agentTomlPath2(root);
@@ -13528,7 +13715,7 @@ function persistedPackaging2(agentRoot2) {
13528
13715
  }
13529
13716
  try {
13530
13717
  const cfg = loadStudioToml19(tomlPath);
13531
- const value = tableOf11(cfg, "deploy").packaging;
13718
+ const value = tableOf12(cfg, "deploy").packaging;
13532
13719
  return value ? String(value) : null;
13533
13720
  } catch {
13534
13721
  return null;
@@ -13539,7 +13726,7 @@ function resolvePlatformArtifact2(agentRoot2) {
13539
13726
  if (isFile14(tomlPath)) {
13540
13727
  try {
13541
13728
  const cfg = loadStudioToml19(tomlPath);
13542
- const explicit = tableOf11(cfg, "deploy").platform_artifact;
13729
+ const explicit = tableOf12(cfg, "deploy").platform_artifact;
13543
13730
  if (explicit) {
13544
13731
  return String(explicit);
13545
13732
  }
@@ -13551,7 +13738,7 @@ function resolvePlatformArtifact2(agentRoot2) {
13551
13738
  function platformPackaging(root) {
13552
13739
  const agentRoot2 = findSubProjectRoot15("agent", root);
13553
13740
  const platformArtifact2 = agentRoot2 !== null ? resolvePlatformArtifact2(agentRoot2) : "zip";
13554
- const walletKind2 = agentRoot2 !== null ? String(tableOf11(loadCfgAt(agentRoot2), "wallet").kind ?? "evm-local") : "evm-local";
13741
+ const walletKind2 = agentRoot2 !== null ? String(tableOf12(loadCfgAt(agentRoot2), "wallet").kind ?? "evm-local") : "evm-local";
13555
13742
  if (walletKind2 === "twak") {
13556
13743
  return "container";
13557
13744
  }
@@ -13569,7 +13756,7 @@ function recordExposedAddress(root, address) {
13569
13756
  if (tomlPath === null) {
13570
13757
  return;
13571
13758
  }
13572
- const existing = tableOf11(
13759
+ const existing = tableOf12(
13573
13760
  loadAgentCfg(root),
13574
13761
  WALLET_SECTION
13575
13762
  ).platform_exposed_addresses;
@@ -13589,7 +13776,7 @@ function utcStamp() {
13589
13776
  function buyerAccess(root) {
13590
13777
  const base = bnbPlatformApiUrl();
13591
13778
  const cfg = loadAgentCfg(root);
13592
- const faces = stackFaces(tableOf11(cfg, "stack"), tableOf11(cfg, "payments"));
13779
+ const faces = stackFaces(tableOf12(cfg, "stack"), tableOf12(cfg, "payments"));
13593
13780
  const protocol = nativeProtocolOf(faces);
13594
13781
  const rawAgentId = platformCfg(root).agent_id;
13595
13782
  const agentId = typeof rawAgentId === "string" && rawAgentId ? rawAgentId : null;
@@ -13633,7 +13820,7 @@ function resolveSlug(root) {
13633
13820
  if (typeof recorded === "string" && recorded) {
13634
13821
  return recorded;
13635
13822
  }
13636
- let name = String(tableOf11(loadAgentCfg(root), "project").name ?? "");
13823
+ let name = String(tableOf12(loadAgentCfg(root), "project").name ?? "");
13637
13824
  name = name.replace(/-(agent|service)$/, "");
13638
13825
  if (!name) {
13639
13826
  name = path36.basename(findWorkspaceRoot6(root) ?? root);
@@ -13713,6 +13900,11 @@ async function platformAgent(opts) {
13713
13900
  }
13714
13901
  const secrets = await (opts.collectRuntimeSecrets ?? collectRuntimeSecrets)(root);
13715
13902
  walletWarning(root, secrets);
13903
+ if (Object.keys(secrets).length > 0) {
13904
+ warn(
13905
+ `note: runtime secret keys handed to the platform: ${Object.keys(secrets).sort().join(", ")} (names only \u2014 values not printed).`
13906
+ );
13907
+ }
13716
13908
  if (!opts.skipPrepare && opts.runPrepareGate) {
13717
13909
  const rc = await opts.runPrepareGate(root, opts.force ?? false);
13718
13910
  if (rc !== null && rc !== 0) {
@@ -13723,6 +13915,18 @@ async function platformAgent(opts) {
13723
13915
  }
13724
13916
  }
13725
13917
  const slug = resolveSlug(root);
13918
+ {
13919
+ const reason = await retiredSlugPreflight(slug, platformCmd);
13920
+ if (reason !== null) {
13921
+ const next = suggestNextSlug(slug);
13922
+ warn(
13923
+ `error: the slug '${slug}' is ${reason} on the platform \u2014 deploys to it always fail (destroyed slugs are permanently retired). Pick a new slug:
13924
+ bag config set deploy.platform.slug ${next}
13925
+ then re-run the deploy.`
13926
+ );
13927
+ return 1;
13928
+ }
13929
+ }
13726
13930
  const agentDir = findSubProjectRoot15("agent", root);
13727
13931
  if (agentDir === null) {
13728
13932
  warn(
@@ -13731,7 +13935,7 @@ async function platformAgent(opts) {
13731
13935
  return 1;
13732
13936
  }
13733
13937
  const cfg = loadAgentCfg(root);
13734
- const faces = stackFaces(tableOf11(cfg, "stack"), tableOf11(cfg, "payments"));
13938
+ const faces = stackFaces(tableOf12(cfg, "stack"), tableOf12(cfg, "payments"));
13735
13939
  const protocol = nativeProtocolOf(faces);
13736
13940
  const runDeploy = opts.runDelegatedDeploy ?? (async (o) => withDeployFiles(
13737
13941
  o.root,
@@ -13845,8 +14049,8 @@ async function confirmPackagingDefault(root, packaging, deps) {
13845
14049
  return null;
13846
14050
  }
13847
14051
  const cfg = loadAgentCfg(root);
13848
- const walletKind2 = String(tableOf11(cfg, "wallet").kind ?? "evm-local");
13849
- const destination = String(tableOf11(cfg, "deploy").destination ?? "platform");
14052
+ const walletKind2 = String(tableOf12(cfg, "wallet").kind ?? "evm-local");
14053
+ const destination = String(tableOf12(cfg, "deploy").destination ?? "platform");
13850
14054
  const answer = await deps.promptUser(
13851
14055
  `This project will deploy as a ${packaging} package (wallet.kind=${walletKind2}, destination=${destination}). Continue? [Y/n] `
13852
14056
  );
@@ -13860,7 +14064,7 @@ function walletWarning(root, secrets) {
13860
14064
  if (!WALLET_MATERIAL_KEYS.some((k) => k in secrets)) {
13861
14065
  return;
13862
14066
  }
13863
- const address = tableOf11(loadAgentCfg(root), "wallet").address;
14067
+ const address = tableOf12(loadAgentCfg(root), "wallet").address;
13864
14068
  const who = typeof address === "string" && address ? `key (address ${address})` : "signing key";
13865
14069
  warn(
13866
14070
  `
@@ -13906,7 +14110,7 @@ function recordShippedWallet(root, secrets) {
13906
14110
  if (!WALLET_MATERIAL_KEYS.some((k) => k in secrets)) {
13907
14111
  return;
13908
14112
  }
13909
- const address = tableOf11(loadAgentCfg(root), "wallet").address;
14113
+ const address = tableOf12(loadAgentCfg(root), "wallet").address;
13910
14114
  if (typeof address === "string" && address) {
13911
14115
  recordExposedAddress(root, address);
13912
14116
  }
@@ -13938,7 +14142,7 @@ function printAccessNextSteps(root, _invokeUrl) {
13938
14142
  }
13939
14143
  if (!x402Only) {
13940
14144
  emit(
13941
- " mint buyer creds: bag platform invoke-client new (prints client_id + client_secret to POST to the client_credentials token endpoint above)"
14145
+ " mint buyer creds: bag platform invoke-client new (prints client_id + client_secret to POST to the client_credentials token endpoint above \u2014 credentials go in the form BODY; HTTP Basic auth is not accepted)"
13942
14146
  );
13943
14147
  } else {
13944
14148
  emit(" protocol discovery is suppressed for this X402-only deployment.");
@@ -13989,6 +14193,8 @@ function printAgentClientPrompt(root, invokeUrl, status) {
13989
14193
  const agentIdNote = agentId ?? "<not registered yet \u2014 run `bag platform invoke-client new` to get one>";
13990
14194
  const tokenSteps = ` 1) run \`bag platform invoke-client new\` -> client_id + client_secret (secret shown ONCE).
13991
14195
  2) POST client_credentials to ${tokenUrl} with scope \`${scope}\` -> access_token.
14196
+ Send client_id + client_secret in the application/x-www-form-urlencoded BODY \u2014
14197
+ this endpoint does NOT accept HTTP Basic auth (\`curl -u\` fails with oauth.invalid_request).
13992
14198
  3) send \`Authorization: Bearer <token>\`.`;
13993
14199
  const agentCfg = loadAgentCfg(agentRoot2);
13994
14200
  const rails = commerceRails(agentCfg);
@@ -13999,7 +14205,10 @@ function printAgentClientPrompt(root, invokeUrl, status) {
13999
14205
  if (hasA2aFace(faces)) {
14000
14206
  endpoints.push(
14001
14207
  ` [A2A] Agent card: ${cardUrl}
14002
- Invoke (JSON-RPC message/send): ${a2aInvokeUrl}`
14208
+ Invoke (JSON-RPC message/send): ${a2aInvokeUrl}
14209
+ When composing agent-card URLs in code, build them with \`new URL(base)\` +
14210
+ \`url.pathname = ... \` (keeps any querystring intact) \u2014 never string-concatenate
14211
+ \`\${base}/.well-known/agent-card.json\`; that breaks on URLs that carry a querystring.`
14003
14212
  );
14004
14213
  }
14005
14214
  if (hasMcpFace(faces)) {
@@ -14204,7 +14413,8 @@ async function platformDestroy(opts) {
14204
14413
  return 1;
14205
14414
  }
14206
14415
  const oldInvokeUrl = recorded.invoke_url;
14207
- recordPlatformKv(root, "slug", "");
14416
+ const nextSlug = suggestNextSlug(slug);
14417
+ recordPlatformKv(root, "slug", nextSlug);
14208
14418
  recordPlatformKv(root, "deployment_id", "");
14209
14419
  recordPlatformKv(root, "invoke_url", "");
14210
14420
  recordPlatformKv(root, "agent_id", "");
@@ -14215,11 +14425,10 @@ async function platformDestroy(opts) {
14215
14425
  );
14216
14426
  emit(`\u2713 deleted platform agent ${slug} (deployment + transmitted secret).`);
14217
14427
  emit(
14218
- "note: the on-chain ERC-8004 identity is unchanged; its endpoint will go stale. The platform slug was cleared locally because destroyed slugs are permanently retired. Your local keystore (.studio/wallets/) was left untouched."
14428
+ `note: the on-chain ERC-8004 identity is unchanged; its endpoint will go stale. Destroyed slugs are permanently retired, so the local slug was advanced to '${nextSlug}' \u2014 the next deploy uses it automatically. Your local keystore (.studio/wallets/) was left untouched.`
14219
14429
  );
14220
14430
  emit(
14221
- ` Redeploying THIS project needs a fresh slug (the old one is retired):
14222
- bag config set deploy.platform.slug ${suggestNextSlug(slug)}
14431
+ ` Redeploy THIS project (uses '${nextSlug}', or pick your own with \`bag config set deploy.platform.slug <name>\`):
14223
14432
  bag deploy --provider bnb`
14224
14433
  );
14225
14434
  return 0;
@@ -14267,7 +14476,7 @@ function isDir7(p) {
14267
14476
  function errMsg2(exc) {
14268
14477
  return exc instanceof Error ? exc.message : String(exc);
14269
14478
  }
14270
- function tableOf12(cfg, key) {
14479
+ function tableOf13(cfg, key) {
14271
14480
  const v = cfg[key];
14272
14481
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
14273
14482
  }
@@ -14439,8 +14648,8 @@ function registerDeploy(program) {
14439
14648
  p.command("fix-gitignore").description(
14440
14649
  "Ensure the workspace .gitignore excludes .studio/ (the agent's .env.local + keystore)."
14441
14650
  ).option("--project-root <path>", "Override project root.").action(act((opts) => cmdFixGitignore(opts)));
14442
- p.command("provision-cognito").description(
14443
- "Emit an AWS CDK app under agentcore/cognito/ that provisions a Cognito M2M client for the AgentCore A2A inbound OAuth2 authorizer (studio writes IaC + prints steps; you run `cdk deploy`)."
14651
+ p.command("provision-cognito", { hidden: true }).description(
14652
+ "DEPRECATED \u2014 `bag deploy` provisions inbound OAuth by itself. Emit an AWS CDK app under agentcore/cognito/ that provisions a Cognito M2M client for the AgentCore inbound OAuth2 authorizer (studio writes IaC + prints steps; you run `cdk deploy`)."
14444
14653
  ).option("--project-root <path>", "Override project root.").option(
14445
14654
  "--wire [outputsFile]",
14446
14655
  "After you `cdk deploy --outputs-file <file>`, wire those outputs into agentcore.json + .studio/.env.local (default file: agentcore/cognito/cdk-outputs.json). Pure local file I/O \u2014 studio never calls AWS."
@@ -14479,7 +14688,7 @@ function readStackRuntime(root) {
14479
14688
  if (cfg === null) {
14480
14689
  return null;
14481
14690
  }
14482
- const runtime = tableOf12(cfg, "stack").runtime;
14691
+ const runtime = tableOf13(cfg, "stack").runtime;
14483
14692
  return runtime ? String(runtime) : null;
14484
14693
  }
14485
14694
  function agentNetworkDefault(root) {
@@ -14487,24 +14696,29 @@ function agentNetworkDefault(root) {
14487
14696
  if (cfg === null) {
14488
14697
  return "";
14489
14698
  }
14490
- return String(tableOf12(cfg, "network").default ?? "").toLowerCase();
14699
+ return String(tableOf13(cfg, "network").default ?? "").toLowerCase();
14491
14700
  }
14492
14701
  function agentDeployDestination(root) {
14493
14702
  const cfg = loadAgentCfg2(root);
14494
14703
  if (cfg === null) {
14495
14704
  return "self";
14496
14705
  }
14497
- const dest = String(tableOf12(cfg, "deploy").destination ?? "").trim().toLowerCase();
14706
+ const dest = String(tableOf13(cfg, "deploy").destination ?? "").trim().toLowerCase();
14498
14707
  return dest || "self";
14499
14708
  }
14500
14709
  function resolveTarget(opts, root, destination = agentDeployDestination(root)) {
14501
14710
  const explicit = opts.runtime ?? opts.target;
14502
- if (explicit) {
14503
- return explicit;
14504
- }
14505
14711
  if (destination === "platform") {
14712
+ if (explicit && explicit !== "platform") {
14713
+ printErr(
14714
+ `warning: --runtime=${explicit} ignored \u2014 studio.toml has [deploy].destination = 'platform', which selects the managed deploy path and its own checks. Use --provider bnb|aws to pick where this agent deploys.`
14715
+ );
14716
+ }
14506
14717
  return "platform";
14507
14718
  }
14719
+ if (explicit) {
14720
+ return explicit;
14721
+ }
14508
14722
  return readStackRuntime(root) ?? "agentcore";
14509
14723
  }
14510
14724
  function validateRuntimeAgainstStack(target, force, root) {
@@ -14711,6 +14925,12 @@ function writeAgentDeployState(workspaceRoot, arn, record = {}, destination = "s
14711
14925
  if (scope) {
14712
14926
  setEnvVar(envLocalPath16(agentRoot2), "OAUTH_SCOPE", scope);
14713
14927
  }
14928
+ syncDescriptorOauthFacts(workspaceRoot, {
14929
+ tokenUrl,
14930
+ scope,
14931
+ discoveryUrl,
14932
+ clientId
14933
+ });
14714
14934
  if (persistedPackaging(agentRoot2) === null) {
14715
14935
  patchTomlKv(
14716
14936
  tomlPath,
@@ -14976,6 +15196,17 @@ async function refreshLocalDeployDependencies(root) {
14976
15196
  return 1;
14977
15197
  }
14978
15198
  }
15199
+ function partialDeployCleanupNote(workspaceRoot) {
15200
+ const project = projectName(workspaceRoot);
15201
+ return [
15202
+ "note: a deploy that fails partway can leave these behind (they are reused by a successful retry, so clean up only if you are giving up):",
15203
+ ` - ECR image bnbagent/${project}`,
15204
+ ` - Secrets Manager bnbagent/${project}/runtime`,
15205
+ ` - Cognito M2M client bnbagent-${project}`,
15206
+ ` - IAM role bnbagent-${project}-runtime`,
15207
+ " `bag deploy destroy --provider aws --execute` removes the runtime, secret, and M2M client; add --purge for the ECR repository and log groups. The IAM role is deleted with the runtime it was created for."
15208
+ ].join("\n");
15209
+ }
14979
15210
  async function cmdAgent(opts, agentcoreArgs) {
14980
15211
  let rc = applyProjectRoot(opts.projectRoot);
14981
15212
  if (rc !== null) {
@@ -15187,6 +15418,7 @@ async function cmdAgent(opts, agentcoreArgs) {
15187
15418
  printErr(
15188
15419
  "note: the pinned bnbagent-deploy adapter automatically restores an owned runtime secret that is inside its recovery window. If AWS denies that operation, update the deployer policy to include secretsmanager:RestoreSecret."
15189
15420
  );
15421
+ printErr(partialDeployCleanupNote(workspaceRoot));
15190
15422
  return code;
15191
15423
  }
15192
15424
  const record = recordOf2(data);
@@ -15246,13 +15478,13 @@ function recordedEndpoint(root) {
15246
15478
  if (cfg === null) {
15247
15479
  return null;
15248
15480
  }
15249
- const url = tableOf12(cfg, "identity").endpoint;
15481
+ const url = tableOf13(cfg, "identity").endpoint;
15250
15482
  return url ? String(url) : null;
15251
15483
  }
15252
15484
  function recordedAgentId(agentRoot2) {
15253
15485
  try {
15254
15486
  const cfg = loadStudioToml20(path37.join(agentRoot2, "studio.toml"));
15255
- const val = tableOf12(cfg, "identity").agent_id;
15487
+ const val = tableOf13(cfg, "identity").agent_id;
15256
15488
  return val !== void 0 && val !== null && val !== "" ? String(val) : null;
15257
15489
  } catch {
15258
15490
  return null;
@@ -15261,7 +15493,7 @@ function recordedAgentId(agentRoot2) {
15261
15493
  function recordedRuntimeArn(agentRoot2) {
15262
15494
  try {
15263
15495
  const cfg = loadStudioToml20(path37.join(agentRoot2, "studio.toml"));
15264
- const val = tableOf12(cfg, "deploy").runtime_arn;
15496
+ const val = tableOf13(cfg, "deploy").runtime_arn;
15265
15497
  return val ? String(val) : null;
15266
15498
  } catch {
15267
15499
  return null;
@@ -15270,7 +15502,7 @@ function recordedRuntimeArn(agentRoot2) {
15270
15502
  function recordedOauthClientId(agentRoot2) {
15271
15503
  try {
15272
15504
  const cfg = loadStudioToml20(path37.join(agentRoot2, "studio.toml"));
15273
- const val = tableOf12(cfg, "deploy").oauth_client_id;
15505
+ const val = tableOf13(cfg, "deploy").oauth_client_id;
15274
15506
  return val ? String(val) : null;
15275
15507
  } catch {
15276
15508
  return null;
@@ -15279,7 +15511,7 @@ function recordedOauthClientId(agentRoot2) {
15279
15511
  function agentFacesOf(agentRoot2) {
15280
15512
  try {
15281
15513
  const cfg = loadStudioToml20(path37.join(agentRoot2, "studio.toml"));
15282
- return stackFaces(tableOf12(cfg, "stack"), tableOf12(cfg, "payments"));
15514
+ return stackFaces(tableOf13(cfg, "stack"), tableOf13(cfg, "payments"));
15283
15515
  } catch {
15284
15516
  return ["A2A"];
15285
15517
  }
@@ -15372,7 +15604,10 @@ async function printAgentClientPrompt2(root, destination, opts = {}) {
15372
15604
  and POST it to the invoke URL above.` : ` [A2A] Invoke (JSON-RPC message/send, POST-only): ${a2aInvokeUrl}
15373
15605
  NOTE: this AgentCore endpoint is POST-only and serves NO
15374
15606
  GET-able agent card. Skip A2A discovery (do NOT fetch
15375
- /.well-known/agent-card.json) \u2014 ${a2aPayloadPhrase} straight to the invoke URL above.`;
15607
+ /.well-known/agent-card.json) \u2014 ${a2aPayloadPhrase} straight to the invoke URL above.
15608
+ The invoke URL carries a querystring (?qualifier=...): never
15609
+ string-concatenate extra path segments onto it \u2014 that produces
15610
+ an invalid URL and an HTTP 405.`;
15376
15611
  const lines = [
15377
15612
  "",
15378
15613
  CLIENT_PROMPT_RULE2,
@@ -15526,6 +15761,7 @@ function verifyToJson(r) {
15526
15761
  studio_toml_updated: r.studioTomlUpdated,
15527
15762
  runtime: r.runtime,
15528
15763
  note: r.note,
15764
+ warning: r.warning,
15529
15765
  error: r.error,
15530
15766
  exit_code: r.exitCode
15531
15767
  };
@@ -15567,12 +15803,15 @@ function renderVerifyHuman(r, deployment, liveStatus) {
15567
15803
  if (r.note) {
15568
15804
  printOut(`note: ${r.note}`);
15569
15805
  }
15806
+ if (r.warning) {
15807
+ printOut(`warning: ${r.warning}`);
15808
+ }
15570
15809
  if (r.error) {
15571
15810
  printOut(`error: ${r.error}`);
15572
15811
  }
15573
15812
  }
15574
15813
  function deployCliError(data) {
15575
- const error = tableOf12(data, "error");
15814
+ const error = tableOf13(data, "error");
15576
15815
  const message = String(error.message ?? "").trim();
15577
15816
  return message || null;
15578
15817
  }
@@ -15914,6 +16153,7 @@ async function cmdFixGitignore(opts) {
15914
16153
  printOut(`${marker} ${result.name}: ${result.message}`);
15915
16154
  return 0;
15916
16155
  }
16156
+ var PROVISION_COGNITO_DEPRECATION = "warning: `bag deploy provision-cognito` is deprecated and will be removed.\n `bag deploy` provisions the inbound OAuth user pool and M2M client on its\n own; the pool this CDK app stands up is never used by a deploy, and both\n the stack and its client are billable orphans you have to clean up.\n Run `bag deploy --provider aws` directly instead.";
15917
16157
  async function cmdProvisionCognito(opts) {
15918
16158
  const rc = applyProjectRoot(opts.projectRoot, false);
15919
16159
  if (rc !== null) {
@@ -15921,6 +16161,7 @@ async function cmdProvisionCognito(opts) {
15921
16161
  }
15922
16162
  const root = resolveProjectRoot2(opts.projectRoot);
15923
16163
  const workspaceRoot = deployWorkspaceRoot2(root);
16164
+ printOut(PROVISION_COGNITO_DEPRECATION);
15924
16165
  if (opts.wire !== void 0 && opts.wire !== false) {
15925
16166
  const outputsFile = typeof opts.wire === "string" && opts.wire ? opts.wire : null;
15926
16167
  try {
@@ -15987,7 +16228,7 @@ var SECRET_ENV_KEYS = [
15987
16228
  "TWAK_ACCESS_ID",
15988
16229
  "TWAK_HMAC_SECRET"
15989
16230
  ];
15990
- function tableOf13(cfg, key) {
16231
+ function tableOf14(cfg, key) {
15991
16232
  const v = cfg[key];
15992
16233
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
15993
16234
  }
@@ -16064,7 +16305,7 @@ async function cmdDoctor(opts) {
16064
16305
  checks.push(...await checkBalances(projectRoot, data, opts.network));
16065
16306
  checks.push(...await checkPieverseMainnetU(projectRoot, data));
16066
16307
  checks.push(...await check8004(projectRoot, data, opts.network));
16067
- const destination = String(tableOf13(data, "deploy").destination ?? "self").trim().toLowerCase();
16308
+ const destination = String(tableOf14(data, "deploy").destination ?? "self").trim().toLowerCase();
16068
16309
  checks.push(...await checkDeployTools(data, destination));
16069
16310
  checks.push(...checkAgentsMdSkillTrigger(projectRoot));
16070
16311
  printChecks(checks);
@@ -16147,13 +16388,13 @@ function checkAppMain(projectRootArg) {
16147
16388
  config = {};
16148
16389
  }
16149
16390
  }
16150
- const stack = tableOf13(config, "stack");
16391
+ const stack = tableOf14(config, "stack");
16151
16392
  const runtime = String(stack.runtime ?? "").toLowerCase();
16152
16393
  let entrypoint;
16153
16394
  if (runtime === "azure-foundry") {
16154
16395
  entrypoint = "src/foundryMain.ts";
16155
16396
  } else if (runtime === "agentcore") {
16156
- const faces = stackFaces(stack, tableOf13(config, "payments"));
16397
+ const faces = stackFaces(stack, tableOf14(config, "payments"));
16157
16398
  entrypoint = `src/${entryStemOf(faces)}.ts`;
16158
16399
  } else {
16159
16400
  entrypoint = "src/main.ts";
@@ -16224,7 +16465,7 @@ function anchoredKeystoreDir(projectRoot, walletCfg) {
16224
16465
  return path38.isAbsolute(rel) ? rel : path38.join(projectRoot, rel);
16225
16466
  }
16226
16467
  async function checkWallet(projectRoot, data) {
16227
- const walletCfg = tableOf13(data, "wallet");
16468
+ const walletCfg = tableOf14(data, "wallet");
16228
16469
  if (walletCfg.kind === "twak") {
16229
16470
  return checkWalletTwak(walletCfg, projectRoot, data);
16230
16471
  }
@@ -16396,7 +16637,7 @@ async function checkWalletTwak(walletCfg, projectRoot, data = {}) {
16396
16637
  detail: `not on PATH \u2014 npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
16397
16638
  });
16398
16639
  }
16399
- const networkName = String(tableOf13(data, "network").default ?? "bsc-testnet");
16640
+ const networkName = String(tableOf14(data, "network").default ?? "bsc-testnet");
16400
16641
  const unsupportedTargets = twakUnsupportedContractOverrides(networkName);
16401
16642
  if (unsupportedTargets.length > 0) {
16402
16643
  out.push({
@@ -16442,7 +16683,7 @@ async function checkWalletTwak(walletCfg, projectRoot, data = {}) {
16442
16683
  return out;
16443
16684
  }
16444
16685
  function checkPassword(data) {
16445
- const walletKind2 = String(tableOf13(data, "wallet").kind ?? "evm-local");
16686
+ const walletKind2 = String(tableOf14(data, "wallet").kind ?? "evm-local");
16446
16687
  if (walletKind2 === "twak") {
16447
16688
  if (process.env.TWAK_WALLET_PASSWORD) {
16448
16689
  return [
@@ -16478,7 +16719,7 @@ function checkPassword(data) {
16478
16719
  ];
16479
16720
  }
16480
16721
  async function checkLlm(data, projectRoot) {
16481
- const llmCfg = tableOf13(data, "llm");
16722
+ const llmCfg = tableOf14(data, "llm");
16482
16723
  const provider = llmCfg.provider ? String(llmCfg.provider) : null;
16483
16724
  if (!provider) {
16484
16725
  return [{ name: "[llm] provider", status: WARN, detail: "not configured" }];
@@ -16523,8 +16764,8 @@ async function checkLlm(data, projectRoot) {
16523
16764
  return out;
16524
16765
  }
16525
16766
  async function checkPieverse(data, apiKey) {
16526
- const llmCfg = tableOf13(data, "llm");
16527
- const pvCfg = tableOf13(llmCfg, "pieverse");
16767
+ const llmCfg = tableOf14(data, "llm");
16768
+ const pvCfg = tableOf14(llmCfg, "pieverse");
16528
16769
  const keyHash = pvCfg.key_hash ? String(pvCfg.key_hash) : null;
16529
16770
  const hasEnv = Boolean(apiKey);
16530
16771
  const out = [];
@@ -16594,8 +16835,8 @@ async function checkPieverse(data, apiKey) {
16594
16835
  });
16595
16836
  }
16596
16837
  try {
16597
- const policy = pieversePolicyFromToml(tableOf13(llmCfg, "auto_renew"));
16598
- const budget = policyFromToml(tableOf13(data, "budget"));
16838
+ const policy = pieversePolicyFromToml(tableOf14(llmCfg, "auto_renew"));
16839
+ const budget = policyFromToml(tableOf14(data, "budget"));
16599
16840
  let detail;
16600
16841
  if (policy.enabled) {
16601
16842
  const allocateDetail = `enabled: allocates $${policy.topupChunkUsd.toFixed(2)} from Account Balance when key < $${policy.minBalanceUsd.toFixed(2)}.`;
@@ -16615,7 +16856,7 @@ async function checkPieverse(data, apiKey) {
16615
16856
  return out;
16616
16857
  }
16617
16858
  async function checkNetwork(data, networkOverride) {
16618
- const netName = networkOverride || tableOf13(data, "network").default;
16859
+ const netName = networkOverride || tableOf14(data, "network").default;
16619
16860
  if (!netName) {
16620
16861
  return [
16621
16862
  {
@@ -16660,7 +16901,7 @@ async function checkNetwork(data, networkOverride) {
16660
16901
  }
16661
16902
  }
16662
16903
  function checkCurrency(data) {
16663
- const payments = tableOf13(data, "payments");
16904
+ const payments = tableOf14(data, "payments");
16664
16905
  const pay = payments.erc8183;
16665
16906
  if (pay === null || typeof pay !== "object" || Array.isArray(pay)) {
16666
16907
  return [];
@@ -16678,7 +16919,7 @@ function checkCurrency(data) {
16678
16919
  return [];
16679
16920
  }
16680
16921
  function checkErc8183Pricing(data) {
16681
- const payValue = tableOf13(data, "payments").erc8183;
16922
+ const payValue = tableOf14(data, "payments").erc8183;
16682
16923
  if (payValue === null || typeof payValue !== "object" || Array.isArray(payValue)) {
16683
16924
  return [];
16684
16925
  }
@@ -16758,7 +16999,7 @@ function checkErc8183Pricing(data) {
16758
16999
  ];
16759
17000
  }
16760
17001
  function checkPriceBounds(data) {
16761
- const payValue = tableOf13(data, "payments").erc8183;
17002
+ const payValue = tableOf14(data, "payments").erc8183;
16762
17003
  if (payValue === null || typeof payValue !== "object" || Array.isArray(payValue)) {
16763
17004
  return [];
16764
17005
  }
@@ -16776,7 +17017,7 @@ function checkPriceBounds(data) {
16776
17017
  return [];
16777
17018
  }
16778
17019
  function checkX402Seller(data, agentRoot2) {
16779
- const payments = tableOf13(data, "payments");
17020
+ const payments = tableOf14(data, "payments");
16780
17021
  const sellerValue = payments.x402_seller;
16781
17022
  if (sellerValue === null || typeof sellerValue !== "object" || Array.isArray(sellerValue)) {
16782
17023
  return [];
@@ -16793,7 +17034,7 @@ function checkX402Seller(data, agentRoot2) {
16793
17034
  }
16794
17035
  ];
16795
17036
  }
16796
- const runtime = String(tableOf13(data, "stack").runtime ?? "agentcore");
17037
+ const runtime = String(tableOf14(data, "stack").runtime ?? "agentcore");
16797
17038
  const hasErc8183 = payments.erc8183 !== null && typeof payments.erc8183 === "object" && !Array.isArray(payments.erc8183);
16798
17039
  const fallbackStatus = hasErc8183 ? WARN : FAIL;
16799
17040
  if (pricing.kind === "free") {
@@ -16828,7 +17069,7 @@ function checkX402Seller(data, agentRoot2) {
16828
17069
  detail: `PAID \u2014 $${pricing.priceUsd} per request through B402.`
16829
17070
  }
16830
17071
  ];
16831
- const walletKind2 = String(tableOf13(data, "wallet").kind ?? "evm-local");
17072
+ const walletKind2 = String(tableOf14(data, "wallet").kind ?? "evm-local");
16832
17073
  if (!["evm-local", "twak"].includes(walletKind2)) {
16833
17074
  out.push({
16834
17075
  name: "x402 payout wallet",
@@ -16854,7 +17095,7 @@ function checkX402Seller(data, agentRoot2) {
16854
17095
  return out;
16855
17096
  }
16856
17097
  function checkStorage(data) {
16857
- const kind = String(tableOf13(data, "storage").kind ?? "local").toLowerCase();
17098
+ const kind = String(tableOf14(data, "storage").kind ?? "local").toLowerCase();
16858
17099
  if (kind === "ipfs") {
16859
17100
  if (!process.env.STORAGE_API_URL) {
16860
17101
  return [
@@ -16900,7 +17141,7 @@ function checkStorage(data) {
16900
17141
  ];
16901
17142
  }
16902
17143
  function balanceAddress(projectRoot, data) {
16903
- const walletCfg = tableOf13(data, "wallet");
17144
+ const walletCfg = tableOf14(data, "wallet");
16904
17145
  if (walletCfg.kind === "twak" || walletCfg.kind === "altana") {
16905
17146
  const addr = String(walletCfg.address ?? "").trim();
16906
17147
  return addr || null;
@@ -16922,7 +17163,7 @@ function balanceAddress(projectRoot, data) {
16922
17163
  return provider.address;
16923
17164
  }
16924
17165
  async function checkBalances(projectRoot, data, networkOverride) {
16925
- const netName = networkOverride || tableOf13(data, "network").default;
17166
+ const netName = networkOverride || tableOf14(data, "network").default;
16926
17167
  if (!netName) {
16927
17168
  return [];
16928
17169
  }
@@ -16999,11 +17240,11 @@ async function checkBalances(projectRoot, data, networkOverride) {
16999
17240
  }
17000
17241
  }
17001
17242
  async function checkPieverseMainnetU(projectRoot, data) {
17002
- const llmCfg = tableOf13(data, "llm");
17243
+ const llmCfg = tableOf14(data, "llm");
17003
17244
  if (llmCfg.provider !== "pieverse-llm") {
17004
17245
  return [];
17005
17246
  }
17006
- const pvCfg = tableOf13(llmCfg, "pieverse");
17247
+ const pvCfg = tableOf14(llmCfg, "pieverse");
17007
17248
  const pvNetwork = String(pvCfg.network ?? "bsc-mainnet");
17008
17249
  if (pvNetwork === "bsc-testnet") {
17009
17250
  return [
@@ -17016,7 +17257,7 @@ async function checkPieverseMainnetU(projectRoot, data) {
17016
17257
  }
17017
17258
  const modelName = String(llmCfg.model ?? "");
17018
17259
  const isFreeModel2 = modelName.includes("auto/free");
17019
- const budgetEnabled = tableOf13(data, "budget").enabled === true;
17260
+ const budgetEnabled = tableOf14(data, "budget").enabled === true;
17020
17261
  if (isFreeModel2 && !budgetEnabled) {
17021
17262
  return [
17022
17263
  {
@@ -17026,7 +17267,7 @@ async function checkPieverseMainnetU(projectRoot, data) {
17026
17267
  }
17027
17268
  ];
17028
17269
  }
17029
- const autoRenew = tableOf13(llmCfg, "auto_renew");
17270
+ const autoRenew = tableOf14(llmCfg, "auto_renew");
17030
17271
  const chunk = typeof autoRenew.topup_chunk_usd === "number" ? autoRenew.topup_chunk_usd : 1;
17031
17272
  const threshold = chunk * 2;
17032
17273
  try {
@@ -17071,7 +17312,7 @@ async function check8004(projectRoot, data, networkOverride) {
17071
17312
  if (!process.env.WALLET_PASSWORD) {
17072
17313
  return [];
17073
17314
  }
17074
- const walletCfg = tableOf13(data, "wallet");
17315
+ const walletCfg = tableOf14(data, "wallet");
17075
17316
  if (!isLocalEvmWallet(walletCfg)) {
17076
17317
  return [];
17077
17318
  }
@@ -17080,7 +17321,7 @@ async function check8004(projectRoot, data, networkOverride) {
17080
17321
  return [];
17081
17322
  }
17082
17323
  const network = String(
17083
- networkOverride || tableOf13(data, "network").default || "bsc-testnet"
17324
+ networkOverride || tableOf14(data, "network").default || "bsc-testnet"
17084
17325
  );
17085
17326
  try {
17086
17327
  const wallet = walletRt5.getWallet();
@@ -17113,11 +17354,11 @@ async function check8004(projectRoot, data, networkOverride) {
17113
17354
  }
17114
17355
  }
17115
17356
  function platformPackagingRequiresContainer(data) {
17116
- const walletKind2 = String(tableOf13(data, "wallet").kind ?? "evm-local").trim().toLowerCase();
17357
+ const walletKind2 = String(tableOf14(data, "wallet").kind ?? "evm-local").trim().toLowerCase();
17117
17358
  if (walletKind2 === "twak") {
17118
17359
  return true;
17119
17360
  }
17120
- const deployCfg = tableOf13(data, "deploy");
17361
+ const deployCfg = tableOf14(data, "deploy");
17121
17362
  let platformArtifact2 = String(deployCfg.platform_artifact ?? "").trim().toLowerCase();
17122
17363
  if (!platformArtifact2) {
17123
17364
  const packaging = String(deployCfg.packaging ?? "").trim().toLowerCase();
@@ -17153,7 +17394,7 @@ async function checkDeployTools(data, destination) {
17153
17394
  detail: "[deploy].platform_artifact='zip' uses the managed platform's ZIP runtime; local Docker is not required."
17154
17395
  });
17155
17396
  }
17156
- const walletKind2 = String(tableOf13(data, "wallet").kind ?? "").trim().toLowerCase();
17397
+ const walletKind2 = String(tableOf14(data, "wallet").kind ?? "").trim().toLowerCase();
17157
17398
  if (walletKind2 === "twak") {
17158
17399
  out.push(emit2(await checkTwak()));
17159
17400
  } else {
@@ -17437,7 +17678,7 @@ function registerErc8004(program) {
17437
17678
  )
17438
17679
  );
17439
17680
  }
17440
- function tableOf14(cfg, key) {
17681
+ function tableOf15(cfg, key) {
17441
17682
  const v = cfg[key];
17442
17683
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
17443
17684
  }
@@ -17460,7 +17701,7 @@ function resolveNetwork2(override) {
17460
17701
  return override;
17461
17702
  }
17462
17703
  const cfg = loadAgentCfg3();
17463
- const net2 = cfg === null ? void 0 : tableOf14(cfg, "network").default;
17704
+ const net2 = cfg === null ? void 0 : tableOf15(cfg, "network").default;
17464
17705
  return net2 ? String(net2) : "bsc-testnet";
17465
17706
  }
17466
17707
  function resolveProtocol(override) {
@@ -17471,7 +17712,7 @@ function resolveProtocol(override) {
17471
17712
  if (cfg === null) {
17472
17713
  return "A2A";
17473
17714
  }
17474
- const faces = stackFaces(tableOf14(cfg, "stack"), tableOf14(cfg, "payments"));
17715
+ const faces = stackFaces(tableOf15(cfg, "stack"), tableOf15(cfg, "payments"));
17475
17716
  if (faces.length === 1 && hasX402Face(faces)) {
17476
17717
  printErr(
17477
17718
  "warning: this X402-only project has no public ERC-8004 protocol face; A2A is only the internal AgentCore protocol declaration."
@@ -17481,13 +17722,13 @@ function resolveProtocol(override) {
17481
17722
  }
17482
17723
  function recordedEndpoint2() {
17483
17724
  const cfg = loadAgentCfg3();
17484
- const endpoint = cfg === null ? void 0 : tableOf14(cfg, "identity").endpoint;
17725
+ const endpoint = cfg === null ? void 0 : tableOf15(cfg, "identity").endpoint;
17485
17726
  return endpoint ? String(endpoint) : null;
17486
17727
  }
17487
17728
  var REGISTER_MIN_BNB = 2e-3;
17488
17729
  function walletSelfPaysGas() {
17489
17730
  const cfg = loadAgentCfg3();
17490
- if (cfg !== null && tableOf14(cfg, "wallet").gasless) {
17731
+ if (cfg !== null && tableOf15(cfg, "wallet").gasless) {
17491
17732
  return false;
17492
17733
  }
17493
17734
  return true;
@@ -17527,7 +17768,7 @@ function syncAgentRegistry(agentId, op) {
17527
17768
  function loadIdentityBlock(agentRoot2) {
17528
17769
  try {
17529
17770
  return {
17530
- ...tableOf14(
17771
+ ...tableOf15(
17531
17772
  loadStudioToml22(path40.join(agentRoot2, "studio.toml")),
17532
17773
  "identity"
17533
17774
  )
@@ -17630,7 +17871,7 @@ function printPartialRegister(exc) {
17630
17871
  }
17631
17872
  async function cmdRegister2(opts) {
17632
17873
  const cfg = loadAgentCfg3();
17633
- const destination = cfg === null ? "" : String(tableOf14(cfg, "deploy").destination ?? "").trim().toLowerCase();
17874
+ const destination = cfg === null ? "" : String(tableOf15(cfg, "deploy").destination ?? "").trim().toLowerCase();
17634
17875
  if (destination === "platform") {
17635
17876
  printErr(
17636
17877
  "error: this is a platform-destination project \u2014 ERC-8004 registration is relayed GASLESSLY by the BNB Chain operator, not broadcast from your local wallet.\n Use: bag deploy verify --endpoint <your-invoke-url>\n(`bag erc8004 register` always self-pays gas from the local wallet, which fails on the zero-balance throwaway wallet the trial uses.)"
@@ -17934,7 +18175,12 @@ function registerErc8183(program) {
17934
18175
  "--agent-id <id>",
17935
18176
  "ERC-8004 agent_id (resolves provider + negotiates).",
17936
18177
  (v) => Number.parseInt(v, 10)
17937
- ).argument("[task]", "Task description (or use --task).").option("--task <text>", "Task description (alternative to positional).").option(
18178
+ ).argument("[task]", "Task description (or use --task).").option("--task <text>", "Task description (alternative to positional).").addOption(
18179
+ new Option6(
18180
+ "--quote-json <json|path>",
18181
+ "A seller's signed quote envelope (the negotiate response JSON, inline or a file path) to anchor on-chain. Use with --provider for sellers whose negotiate step ran out-of-band (e.g. an OAuth-gated AgentCore seller)."
18182
+ ).conflicts("agentId")
18183
+ ).option(
17938
18184
  "--budget-u <amount>",
17939
18185
  "Max U to spend (default: negotiated or policy)."
17940
18186
  ).option(
@@ -18061,6 +18307,35 @@ async function cmdList3(opts) {
18061
18307
  }
18062
18308
  return 0;
18063
18309
  }
18310
+ function parseQuoteEnvelope(raw) {
18311
+ const trimmed = raw.trim();
18312
+ let text2 = trimmed;
18313
+ if (!trimmed.startsWith("{")) {
18314
+ try {
18315
+ text2 = fs40.readFileSync(trimmed, "utf-8");
18316
+ } catch (exc) {
18317
+ throw new Error(
18318
+ `--quote-json is neither inline JSON nor a readable file: ${errMsg5(exc)}`
18319
+ );
18320
+ }
18321
+ }
18322
+ let parsed;
18323
+ try {
18324
+ parsed = JSON.parse(text2);
18325
+ } catch (exc) {
18326
+ throw new Error(`--quote-json is not valid JSON: ${errMsg5(exc)}`);
18327
+ }
18328
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
18329
+ throw new Error("--quote-json must decode to a JSON object.");
18330
+ }
18331
+ const envelope = parsed;
18332
+ if (!envelope.negotiation_hash || !envelope.provider_sig) {
18333
+ throw new Error(
18334
+ "--quote-json is not a signed quote envelope: it must carry `negotiation_hash` and `provider_sig` (the seller's negotiate response). Re-run the negotiate step and pass its full response body."
18335
+ );
18336
+ }
18337
+ return envelope;
18338
+ }
18064
18339
  async function cmdBuy(taskPositional, opts) {
18065
18340
  const rc = applyProjectRoot2(opts.projectRoot);
18066
18341
  if (rc !== null) {
@@ -18070,6 +18345,15 @@ async function cmdBuy(taskPositional, opts) {
18070
18345
  printErr("error: one of --provider / --agent-id is required");
18071
18346
  return 2;
18072
18347
  }
18348
+ let negotiationEnvelope = null;
18349
+ if (opts.quoteJson !== void 0) {
18350
+ try {
18351
+ negotiationEnvelope = parseQuoteEnvelope(opts.quoteJson);
18352
+ } catch (exc) {
18353
+ printErr(`error: ${errMsg5(exc)}`);
18354
+ return 2;
18355
+ }
18356
+ }
18073
18357
  if (taskPositional !== void 0 && opts.task !== void 0) {
18074
18358
  printErr(
18075
18359
  "error: pass the task once (either positional or --task, not both)"
@@ -18077,19 +18361,20 @@ async function cmdBuy(taskPositional, opts) {
18077
18361
  return 2;
18078
18362
  }
18079
18363
  const task = taskPositional ?? opts.task;
18080
- if (task === void 0) {
18081
- printErr("error: task is required");
18364
+ if (task === void 0 && negotiationEnvelope === null) {
18365
+ printErr("error: task is required (or pass --quote-json)");
18082
18366
  return 2;
18083
18367
  }
18084
18368
  let r;
18085
18369
  try {
18086
- r = await buyWorkflow(opts.provider ?? null, task, {
18370
+ r = await buyWorkflow(opts.provider ?? null, task ?? "", {
18087
18371
  agentId: opts.agentId ?? null,
18088
18372
  budgetU: opts.budgetU ?? null,
18089
18373
  deadlineMinutes: opts.deadlineMin,
18090
18374
  network: opts.network ?? null,
18091
18375
  negotiate: opts.negotiate,
18092
- protocol: opts.protocol
18376
+ protocol: opts.protocol,
18377
+ negotiationEnvelope
18093
18378
  });
18094
18379
  } catch (exc) {
18095
18380
  printErr(`error: ${errMsg5(exc)}`);
@@ -19328,6 +19613,9 @@ function registerX402(program) {
19328
19613
  ).option("--method <verb>", "HTTP verb to send (default: GET).", "GET").option(
19329
19614
  "--json <body>",
19330
19615
  "JSON body to send with the request (a string parsed as JSON)."
19616
+ ).option(
19617
+ "--local-dev",
19618
+ "DEV ONLY: skip the host allowlist for a localhost/127.0.0.1 target."
19331
19619
  ).action(
19332
19620
  act(
19333
19621
  (url, opts) => cmdQuote(url, opts)
@@ -19343,6 +19631,9 @@ function registerX402(program) {
19343
19631
  ).option("--method <verb>", "HTTP verb to send (default: GET).", "GET").option(
19344
19632
  "--json <body>",
19345
19633
  "JSON body to send with the request (a string parsed as JSON)."
19634
+ ).option(
19635
+ "--local-dev",
19636
+ "DEV ONLY: for a localhost/127.0.0.1 target, skip the host allowlist and accept the challenge's payTo as the recipient (printed loudly)."
19346
19637
  ).action(
19347
19638
  act(
19348
19639
  (url, opts) => cmdBuy2(url, opts)
@@ -19394,6 +19685,23 @@ function hostOf(url) {
19394
19685
  return "";
19395
19686
  }
19396
19687
  }
19688
+ function isLoopbackHost(host) {
19689
+ const h = host.toLowerCase().replace(/^\[|\]$/g, "");
19690
+ return h === "localhost" || h === "127.0.0.1" || h === "::1";
19691
+ }
19692
+ function printLocalDevHint(url) {
19693
+ printErr("hint: local dev seller detected. One command sets up everything:");
19694
+ printErr(` bag x402 trust ${url.split("?")[0]}`);
19695
+ printErr(
19696
+ " (adds the host to the allowlist AND pins the seller's payTo as the trusted recipient)"
19697
+ );
19698
+ printErr(
19699
+ "Or configure both by hand in studio.toml [payments.x402]: add the host to allowed_hosts and set expected_recipient."
19700
+ );
19701
+ printErr(
19702
+ "For a throwaway check you can also pass --local-dev to `bag x402 buy`/`quote` (loopback targets only)."
19703
+ );
19704
+ }
19397
19705
  function checkHostAllowed(url, allowedHosts) {
19398
19706
  const host = hostOf(url);
19399
19707
  const allowedLower = new Set(
@@ -19401,7 +19709,7 @@ function checkHostAllowed(url, allowedHosts) {
19401
19709
  );
19402
19710
  return allowedLower.has(host);
19403
19711
  }
19404
- function tableOf15(cfg, key) {
19712
+ function tableOf16(cfg, key) {
19405
19713
  const v = cfg[key];
19406
19714
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
19407
19715
  }
@@ -19440,7 +19748,7 @@ function resolveNetwork3(cfg, override) {
19440
19748
  if (override) {
19441
19749
  return override;
19442
19750
  }
19443
- const net2 = tableOf15(cfg, "network").default;
19751
+ const net2 = tableOf16(cfg, "network").default;
19444
19752
  return net2 ? String(net2) : "bsc-mainnet";
19445
19753
  }
19446
19754
  function parseJsonBody(raw) {
@@ -19466,8 +19774,11 @@ function resolveWallet2() {
19466
19774
  return null;
19467
19775
  }
19468
19776
  }
19469
- function printScopeError(host) {
19777
+ function printScopeError(host, url) {
19470
19778
  printErr(`error: ${SCOPE_NOTE.replace("{host}", host)}`);
19779
+ if (url !== void 0 && isLoopbackHost(host)) {
19780
+ printLocalDevHint(url);
19781
+ }
19471
19782
  }
19472
19783
  async function cmdSellInit(priceFlag) {
19473
19784
  const loaded = loadSellerConfig();
@@ -19484,7 +19795,7 @@ async function cmdSellInit(priceFlag) {
19484
19795
  return 2;
19485
19796
  }
19486
19797
  const free = x402SellerPricingState({ price_usd: priceUsd }).kind === "free";
19487
- const walletKind2 = String(tableOf15(cfg, "wallet").kind ?? "evm-local");
19798
+ const walletKind2 = String(tableOf16(cfg, "wallet").kind ?? "evm-local");
19488
19799
  if (!free && !["evm-local", "twak"].includes(walletKind2)) {
19489
19800
  printErr(
19490
19801
  `error: the b402 seller rail supports wallet.kind evm-local or twak only; '${walletKind2}' cannot act as the b402 payout wallet.`
@@ -19644,8 +19955,12 @@ async function cmdQuote(url, opts) {
19644
19955
  printErr(`error: ${errMsg6(exc)}`);
19645
19956
  return 2;
19646
19957
  }
19647
- if (!checkHostAllowed(url, hosts)) {
19648
- printScopeError(hostOf(url) || url);
19958
+ if (opts.localDev && !isLoopbackHost(hostOf(url))) {
19959
+ printErr("error: --local-dev applies to localhost/127.0.0.1 targets only.");
19960
+ return 2;
19961
+ }
19962
+ if (!opts.localDev && !checkHostAllowed(url, hosts)) {
19963
+ printScopeError(hostOf(url) || url, url);
19649
19964
  return 1;
19650
19965
  }
19651
19966
  let body;
@@ -19653,7 +19968,7 @@ async function cmdQuote(url, opts) {
19653
19968
  body = await quoteUrl(url, {
19654
19969
  method: opts.method,
19655
19970
  jsonBody,
19656
- allowedHosts: hosts
19971
+ allowedHosts: opts.localDev ? null : hosts
19657
19972
  });
19658
19973
  } catch (exc) {
19659
19974
  printX402Error(exc);
@@ -19687,8 +20002,12 @@ async function cmdBuy2(url, opts) {
19687
20002
  return 1;
19688
20003
  }
19689
20004
  const [, cfg, hosts] = loaded;
19690
- if (!checkHostAllowed(url, hosts)) {
19691
- printScopeError(hostOf(url) || url);
20005
+ if (opts.localDev && !isLoopbackHost(hostOf(url))) {
20006
+ printErr("error: --local-dev applies to localhost/127.0.0.1 targets only.");
20007
+ return 2;
20008
+ }
20009
+ if (!opts.localDev && !checkHostAllowed(url, hosts)) {
20010
+ printScopeError(hostOf(url) || url, url);
19692
20011
  return 1;
19693
20012
  }
19694
20013
  let jsonBody;
@@ -19699,6 +20018,24 @@ async function cmdBuy2(url, opts) {
19699
20018
  return 2;
19700
20019
  }
19701
20020
  const networkName = resolveNetwork3(cfg, opts.network);
20021
+ let localDevExpectedTo = null;
20022
+ if (opts.localDev) {
20023
+ let challenge;
20024
+ try {
20025
+ challenge = await quoteUrl(url, { method: opts.method, jsonBody });
20026
+ } catch (exc) {
20027
+ printX402Error(exc);
20028
+ return 1;
20029
+ }
20030
+ const selected2 = selectPayable(challenge, networkName);
20031
+ if (selected2 === null) {
20032
+ return 1;
20033
+ }
20034
+ localDevExpectedTo = String(selected2[0].payTo);
20035
+ printOut(
20036
+ `\u26A0 DEV-ONLY --local-dev: accepting the challenge's payTo ${localDevExpectedTo} as the recipient without a configured pin. Never use this outside your own machine.`
20037
+ );
20038
+ }
19702
20039
  const wallet = resolveWallet2();
19703
20040
  if (wallet === null) {
19704
20041
  return 1;
@@ -19743,7 +20080,8 @@ async function cmdBuy2(url, opts) {
19743
20080
  networkName,
19744
20081
  method: opts.method,
19745
20082
  jsonBody,
19746
- allowedHosts: hosts
20083
+ allowedHosts: opts.localDev ? null : hosts,
20084
+ expectedTo: localDevExpectedTo
19747
20085
  });
19748
20086
  if (r.paidUsd !== null) {
19749
20087
  h.extraContext.paid_usd = r.paidUsd;
@@ -19756,6 +20094,9 @@ async function cmdBuy2(url, opts) {
19756
20094
  );
19757
20095
  } catch (exc) {
19758
20096
  printX402Error(exc);
20097
+ if (errName4(exc) === "X402RecipientRequiredError" && isLoopbackHost(hostOf(url))) {
20098
+ printLocalDevHint(url);
20099
+ }
19759
20100
  return 1;
19760
20101
  }
19761
20102
  const paidUsd = result.paidUsd ?? 0;
@@ -19869,10 +20210,19 @@ async function cmdTrust(merchant, opts) {
19869
20210
  if (merchant.includes("://")) {
19870
20211
  probeUrl = merchant;
19871
20212
  host = hostOf(probeUrl);
19872
- if (!probeUrl.toLowerCase().startsWith("https://") || !host) {
19873
- printErr("error: trust-by-URL needs an absolute https:// URL.");
20213
+ const plainHttp = probeUrl.toLowerCase().startsWith("http://");
20214
+ const localDevHttp = plainHttp && isLoopbackHost(host);
20215
+ if (!probeUrl.toLowerCase().startsWith("https://") && !localDevHttp || !host) {
20216
+ printErr(
20217
+ "error: trust-by-URL needs an absolute https:// URL (plain http:// is allowed only for localhost/127.0.0.1 dev sellers)."
20218
+ );
19874
20219
  return 1;
19875
20220
  }
20221
+ if (localDevHttp) {
20222
+ printOut(
20223
+ "\u26A0 DEV-ONLY: trusting a plain-http loopback seller. http:// carries no transport integrity \u2014 never trust it beyond your own machine."
20224
+ );
20225
+ }
19876
20226
  methodHint = null;
19877
20227
  } else {
19878
20228
  rec = RECOMMENDED_MERCHANTS[merchant.toLowerCase()] ?? null;
@@ -19952,7 +20302,7 @@ The merchant may have rotated its address (or the response was tampered with). U
19952
20302
  " \u26A0 MAINNET: calls spend real $U from the agent wallet. The cap above and [budget].max_per_day_usd bound the exposure."
19953
20303
  );
19954
20304
  }
19955
- const projectDefault = tableOf15(cfg, "network").default;
20305
+ const projectDefault = tableOf16(cfg, "network").default;
19956
20306
  if (projectDefault && String(projectDefault) !== networkName) {
19957
20307
  printOut(
19958
20308
  ` note: your project default is ${projectDefault}; this paid capability settles on ${networkName} independently of it.`
@@ -20033,7 +20383,7 @@ function buildProgram() {
20033
20383
  return program;
20034
20384
  }
20035
20385
  function cliVersion() {
20036
- return "0.0.6-alpha.5";
20386
+ return "0.0.6-alpha.7";
20037
20387
  }
20038
20388
 
20039
20389
  // src/cli/updateCheck.ts