@bnbagent/studio-cli 0.0.9 → 0.0.11-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -2
  3. package/dist/_agentcoreName-DZDWEYD3.js +0 -0
  4. package/dist/_twak-4XF4H5PL.js +0 -0
  5. package/dist/bag.js +577 -370
  6. package/dist/chunk-RO726HJG.js +0 -0
  7. package/dist/{chunk-YFEM4564.js → chunk-TTPOH453.js} +79 -37
  8. package/dist/chunk-U7IDQ3K5.js +0 -0
  9. package/dist/{deployCli-NJFCWBSF.js → deployCli-K55GXDVO.js} +1 -1
  10. package/package.json +11 -12
  11. package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +20 -21
  12. package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +36 -0
  13. package/recipes/runtimes/agentcore/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
  14. package/recipes/runtimes/agentcore/recipe.toml +3 -3
  15. package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +25 -23
  16. package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +16 -12
  17. package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +72 -393
  18. package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +160 -43
  19. package/recipes/runtimes/azure-foundry/code/{{PKG}}/sellerCore.ts.tmpl +504 -0
  20. package/recipes/runtimes/azure-foundry/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
  21. package/recipes/runtimes/azure-foundry/recipe.toml +19 -11
  22. package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +6 -4
  23. package/skills/bnbagent-studio.md +2 -2
  24. package/skills/references/bnbagent-studio-adding-to-project.md +1 -1
  25. package/skills/references/bnbagent-studio-buying-from-bazaar.md +1 -1
  26. package/skills/references/bnbagent-studio-operating.md +4 -4
  27. package/skills/references/bnbagent-studio-scaffolding-agent.md +4 -4
  28. package/skills/references/bnbagent-studio-selling-via-8183.md +3 -3
  29. package/skills/references/bnbagent-studio-selling-via-b402.md +2 -2
  30. package/skills/references/bnbagent-studio-use-aws-agentcore.md +1 -1
  31. package/skills/references/bnbagent-studio-use-azure-foundry.md +3 -3
  32. package/skills/references/bnbagent-studio-use-bnb-trial.md +1 -1
  33. package/skills/references/bnbagent-studio-wiring-llm-tools.md +3 -3
  34. package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +0 -347
  35. package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +0 -422
  36. package/recipes/runtimes/azure-foundry/code/{{PKG}}/main.ts.tmpl +0 -196
package/dist/bag.js CHANGED
@@ -6,17 +6,21 @@ import {
6
6
  CliExit,
7
7
  DEFAULT_B402_PRICE_USD,
8
8
  DEFAULT_B402_TESTNET_BASE_URL,
9
+ LEGACY_ENTRY_STEMS,
10
+ X402_CAPABLE_RUNTIMES,
9
11
  act,
10
12
  agentcoreFlavor,
11
13
  b402Credentials,
12
14
  bnbEnv,
13
15
  bnbPlatformApiUrl,
16
+ checkBunx,
14
17
  checkDocker,
15
18
  checkTwak,
16
19
  commerceRails,
17
20
  deployChecks,
18
21
  deployEndpointValue,
19
22
  devPortOf,
23
+ dryRunBundle,
20
24
  entryStemOf,
21
25
  getEnvVar,
22
26
  hasA2aFace,
@@ -44,7 +48,7 @@ import {
44
48
  x402SellerIsFree,
45
49
  x402SellerPricingState,
46
50
  x402SellerUsesB402
47
- } from "./chunk-YFEM4564.js";
51
+ } from "./chunk-TTPOH453.js";
48
52
  import {
49
53
  TWAK_CLI_MIN_VERSION,
50
54
  TWAK_CLI_VERSION,
@@ -222,7 +226,7 @@ import {
222
226
  var CAMPAIGN_DOC_URL = "https://www.bnbchain.org/en/blog/bnb-agent-studio-is-live-on-bnb-chain-ai-agents-from-one-prompt";
223
227
  var CAMPAIGN_CHECK_TIMEOUT_MS = 6e3;
224
228
  async function fetchCampaignActive() {
225
- const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-NJFCWBSF.js");
229
+ const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-K55GXDVO.js");
226
230
  const controller = new AbortController();
227
231
  const timer = setTimeout(() => controller.abort(), CAMPAIGN_CHECK_TIMEOUT_MS);
228
232
  try {
@@ -437,23 +441,88 @@ function findAgentRoot(start) {
437
441
  // src/cli/program.ts
438
442
  import { Command } from "commander";
439
443
 
440
- // src/cli/agents.ts
444
+ // src/cli/_packageMetadata.ts
441
445
  import * as fs3 from "fs";
442
- import * as os from "os";
443
446
  import * as path2 from "path";
447
+ import { fileURLToPath } from "url";
448
+ function packageRoot() {
449
+ let dir = path2.dirname(fileURLToPath(import.meta.url));
450
+ for (; ; ) {
451
+ const packageJson = path2.join(dir, "package.json");
452
+ if (fs3.existsSync(packageJson)) return dir;
453
+ const parent = path2.dirname(dir);
454
+ if (parent === dir) {
455
+ throw new Error("cannot locate the studio-cli package root");
456
+ }
457
+ dir = parent;
458
+ }
459
+ }
460
+ function studioCliVersion() {
461
+ if ("0.0.11-alpha.1") {
462
+ return "0.0.11-alpha.1";
463
+ }
464
+ const file = path2.join(packageRoot(), "package.json");
465
+ const pkg = JSON.parse(fs3.readFileSync(file, "utf-8"));
466
+ const value = String(pkg.version ?? "");
467
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(value)) {
468
+ throw new Error(
469
+ `studio-cli package.json must contain a valid version in ${file}`
470
+ );
471
+ }
472
+ return value;
473
+ }
474
+ function pnpmVersion() {
475
+ if ("10.24.0") {
476
+ return "10.24.0";
477
+ }
478
+ const file = path2.join(packageRoot(), "package.json");
479
+ const pkg = JSON.parse(fs3.readFileSync(file, "utf-8"));
480
+ const value = String(pkg.packageManager ?? "");
481
+ const match = /^pnpm@(.+)$/u.exec(value);
482
+ if (!match?.[1]) {
483
+ throw new Error(
484
+ `studio-cli packageManager must pin pnpm (expected "pnpm@<version>" in ${file})`
485
+ );
486
+ }
487
+ return match[1];
488
+ }
489
+
490
+ // src/cli/agents.ts
491
+ import * as fs4 from "fs";
492
+ import * as os from "os";
493
+ import * as path3 from "path";
444
494
  import { parse, stringify } from "smol-toml";
445
495
 
446
496
  // src/cli/utils/prompt.ts
447
497
  import * as readline from "readline/promises";
498
+ var PromptCancelled = class extends Error {
499
+ constructor() {
500
+ super("prompt cancelled");
501
+ this.name = "PromptCancelled";
502
+ }
503
+ };
504
+ async function ask(rl, question) {
505
+ try {
506
+ return await Promise.race([
507
+ rl.question(question),
508
+ new Promise((_, reject) => {
509
+ rl.once("SIGINT", () => reject(new PromptCancelled()));
510
+ })
511
+ ]);
512
+ } catch (exc) {
513
+ if (exc instanceof PromptCancelled) {
514
+ throw exc;
515
+ }
516
+ return "";
517
+ }
518
+ }
448
519
  async function promptUser(question) {
449
520
  const rl = readline.createInterface({
450
521
  input: process.stdin,
451
522
  output: process.stdout
452
523
  });
453
524
  try {
454
- return await rl.question(question);
455
- } catch {
456
- return "";
525
+ return await ask(rl, question);
457
526
  } finally {
458
527
  rl.close();
459
528
  }
@@ -464,9 +533,7 @@ async function promptUserStderr(question) {
464
533
  output: process.stderr
465
534
  });
466
535
  try {
467
- return await rl.question(question);
468
- } catch {
469
- return "";
536
+ return await ask(rl, question);
470
537
  } finally {
471
538
  rl.close();
472
539
  }
@@ -480,9 +547,7 @@ async function promptHidden(question) {
480
547
  terminal: false
481
548
  });
482
549
  try {
483
- return await rl.question("");
484
- } catch {
485
- return "";
550
+ return await ask(rl, "");
486
551
  } finally {
487
552
  rl.close();
488
553
  process.stderr.write("\n");
@@ -506,18 +571,18 @@ function stdinIsTty() {
506
571
  // src/cli/agents.ts
507
572
  var SCHEMA_VERSION = "1";
508
573
  function registryPath() {
509
- return path2.join(os.homedir(), ".bnbagent-studio", "projects.toml");
574
+ return path3.join(os.homedir(), ".bnbagent-studio", "projects.toml");
510
575
  }
511
576
  var RegistryCorruptError = class extends Error {
512
577
  };
513
578
  function loadDoc() {
514
579
  const file = registryPath();
515
- if (!fs3.existsSync(file)) {
580
+ if (!fs4.existsSync(file)) {
516
581
  return { schema_version: SCHEMA_VERSION, projects: [] };
517
582
  }
518
583
  let text2;
519
584
  try {
520
- text2 = fs3.readFileSync(file, "utf-8");
585
+ text2 = fs4.readFileSync(file, "utf-8");
521
586
  } catch (exc) {
522
587
  throw new RegistryCorruptError(`cannot read ${file}: ${exc}`);
523
588
  }
@@ -538,7 +603,7 @@ function loadDoc() {
538
603
  }
539
604
  function saveDoc(doc) {
540
605
  const file = registryPath();
541
- fs3.mkdirSync(path2.dirname(file), { recursive: true });
606
+ fs4.mkdirSync(path3.dirname(file), { recursive: true });
542
607
  const projects = doc.projects.map((entry) => {
543
608
  const out = {};
544
609
  for (const [k, v] of Object.entries(entry)) {
@@ -548,7 +613,7 @@ function saveDoc(doc) {
548
613
  }
549
614
  return out;
550
615
  });
551
- fs3.writeFileSync(
616
+ fs4.writeFileSync(
552
617
  file,
553
618
  `${stringify({ schema_version: doc.schema_version, projects })}
554
619
  `,
@@ -557,24 +622,24 @@ function saveDoc(doc) {
557
622
  }
558
623
  function isFile(p) {
559
624
  try {
560
- return fs3.statSync(p).isFile();
625
+ return fs4.statSync(p).isFile();
561
626
  } catch {
562
627
  return false;
563
628
  }
564
629
  }
565
630
  function isDir(p) {
566
631
  try {
567
- return fs3.statSync(p).isDirectory();
632
+ return fs4.statSync(p).isDirectory();
568
633
  } catch {
569
634
  return false;
570
635
  }
571
636
  }
572
637
  function agentSubprojectRoot(projectRoot) {
573
638
  for (const candidate of [
574
- path2.join(projectRoot, "app", "agent"),
575
- path2.join(projectRoot, "agent")
639
+ path3.join(projectRoot, "app", "agent"),
640
+ path3.join(projectRoot, "agent")
576
641
  ]) {
577
- if (isFile(path2.join(candidate, "studio.toml"))) {
642
+ if (isFile(path3.join(candidate, "studio.toml"))) {
578
643
  return candidate;
579
644
  }
580
645
  }
@@ -582,9 +647,9 @@ function agentSubprojectRoot(projectRoot) {
582
647
  }
583
648
  function projectStudioToml(projectRoot) {
584
649
  const candidates = [
585
- path2.join(projectRoot, "studio.toml"),
586
- path2.join(projectRoot, "app", "agent", "studio.toml"),
587
- path2.join(projectRoot, "agent", "studio.toml")
650
+ path3.join(projectRoot, "studio.toml"),
651
+ path3.join(projectRoot, "app", "agent", "studio.toml"),
652
+ path3.join(projectRoot, "agent", "studio.toml")
588
653
  ];
589
654
  return candidates.find(isFile) ?? null;
590
655
  }
@@ -595,14 +660,14 @@ function readStudioToml(projectRoot) {
595
660
  `no studio.toml at ${projectRoot}, ${projectRoot}/app/agent, or ${projectRoot}/agent`
596
661
  );
597
662
  }
598
- return parse(fs3.readFileSync(studioToml, "utf-8"));
663
+ return parse(fs4.readFileSync(studioToml, "utf-8"));
599
664
  }
600
665
  function scanWalletAddress(projectRoot) {
601
- const walletsDir = path2.join(projectRoot, ".studio", "wallets");
666
+ const walletsDir = path3.join(projectRoot, ".studio", "wallets");
602
667
  if (!isDir(walletsDir)) {
603
668
  return null;
604
669
  }
605
- for (const child of fs3.readdirSync(walletsDir).sort()) {
670
+ for (const child of fs4.readdirSync(walletsDir).sort()) {
606
671
  if (!child.endsWith(".json")) {
607
672
  continue;
608
673
  }
@@ -617,13 +682,13 @@ function expandUser(p) {
617
682
  if (p === "~") {
618
683
  return os.homedir();
619
684
  }
620
- if (p.startsWith(`~${path2.sep}`) || p.startsWith("~/")) {
621
- return path2.join(os.homedir(), p.slice(2));
685
+ if (p.startsWith(`~${path3.sep}`) || p.startsWith("~/")) {
686
+ return path3.join(os.homedir(), p.slice(2));
622
687
  }
623
688
  return p;
624
689
  }
625
690
  function normalizePath(p) {
626
- return path2.resolve(expandUser(p));
691
+ return path3.resolve(expandUser(p));
627
692
  }
628
693
  function nowIso() {
629
694
  const d = /* @__PURE__ */ new Date();
@@ -644,13 +709,13 @@ function registerProject(projectRootArg2, opts = {}) {
644
709
  }
645
710
  const cfg = readStudioToml(projectRoot);
646
711
  const agentRoot2 = agentSubprojectRoot(projectRoot);
647
- const resolvedName = opts.name ?? (tableOf(cfg, "project").name || path2.basename(projectRoot));
712
+ const resolvedName = opts.name ?? (tableOf(cfg, "project").name || path3.basename(projectRoot));
648
713
  const network = tableOf(cfg, "network").default || "bsc-testnet";
649
714
  const walletAddress = scanWalletAddress(agentRoot2);
650
715
  const llmProvider = tableOf(cfg, "llm").provider || null;
651
716
  const workspaceRoot = findWorkspaceRoot(projectRoot) ?? projectRoot;
652
- const cloud = fs3.existsSync(
653
- path2.join(workspaceRoot, "agentcore", "agentcore.json")
717
+ const cloud = fs4.existsSync(
718
+ path3.join(workspaceRoot, "agentcore", "agentcore.json")
654
719
  ) ? "agentcore" : null;
655
720
  const entryData = {
656
721
  name: resolvedName,
@@ -731,7 +796,7 @@ function listProjects() {
731
796
  }
732
797
  }
733
798
  if (e.cloud === null) {
734
- if (fs3.existsSync(path2.join(p, "agentcore", "agentcore.json"))) {
799
+ if (fs4.existsSync(path3.join(p, "agentcore", "agentcore.json"))) {
735
800
  e.cloud = "agentcore";
736
801
  changed = true;
737
802
  }
@@ -1036,8 +1101,8 @@ function cmdRegister(pathArg, name, agentId) {
1036
1101
  }
1037
1102
 
1038
1103
  // src/cli/audit.ts
1039
- import * as fs4 from "fs";
1040
- import * as path3 from "path";
1104
+ import * as fs5 from "fs";
1105
+ import * as path4 from "path";
1041
1106
 
1042
1107
  // src/cli/_auditRead.ts
1043
1108
  import {
@@ -1114,17 +1179,17 @@ function parseSince(s) {
1114
1179
  return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}.000Z`;
1115
1180
  }
1116
1181
  function resolveProjectRoot(argRoot) {
1117
- const root = argRoot !== void 0 ? path3.resolve(argRoot) : process.cwd();
1118
- if (fs4.existsSync(path3.join(root, "studio.toml"))) {
1182
+ const root = argRoot !== void 0 ? path4.resolve(argRoot) : process.cwd();
1183
+ if (fs5.existsSync(path4.join(root, "studio.toml"))) {
1119
1184
  return root;
1120
1185
  }
1121
1186
  let current = root;
1122
1187
  for (; ; ) {
1123
- const parent = path3.dirname(current);
1188
+ const parent = path4.dirname(current);
1124
1189
  if (parent === current) {
1125
1190
  return null;
1126
1191
  }
1127
- if (fs4.existsSync(path3.join(parent, "studio.toml"))) {
1192
+ if (fs5.existsSync(path4.join(parent, "studio.toml"))) {
1128
1193
  return parent;
1129
1194
  }
1130
1195
  current = parent;
@@ -1200,18 +1265,18 @@ function cmdShow2(txHash, opts) {
1200
1265
  }
1201
1266
 
1202
1267
  // src/cli/budget.ts
1203
- import * as fs6 from "fs";
1204
- import * as path5 from "path";
1268
+ import * as fs7 from "fs";
1269
+ import * as path6 from "path";
1205
1270
  import { BudgetPolicy } from "@bnbagent/studio-runtime/pieverse";
1206
1271
  import { parse as parse3 } from "smol-toml";
1207
1272
 
1208
1273
  // src/cli/_projectRoot.ts
1209
- import * as fs5 from "fs";
1210
- import * as path4 from "path";
1274
+ import * as fs6 from "fs";
1275
+ import * as path5 from "path";
1211
1276
  function resolveProjectRootArg(argRoot) {
1212
1277
  if (argRoot !== void 0) {
1213
- const root2 = path4.resolve(argRoot);
1214
- if (!fs5.existsSync(path4.join(root2, "studio.toml"))) {
1278
+ const root2 = path5.resolve(argRoot);
1279
+ if (!fs6.existsSync(path5.join(root2, "studio.toml"))) {
1215
1280
  printErr(`error: no studio.toml under --project-root ${root2}`);
1216
1281
  return null;
1217
1282
  }
@@ -1486,7 +1551,7 @@ function registerBudget(program) {
1486
1551
  }
1487
1552
  function loadPolicy(root) {
1488
1553
  const cfg = parse3(
1489
- fs6.readFileSync(path5.join(root, "studio.toml"), "utf-8")
1554
+ fs7.readFileSync(path6.join(root, "studio.toml"), "utf-8")
1490
1555
  );
1491
1556
  const budget = cfg.budget;
1492
1557
  return policyFromToml(
@@ -1494,9 +1559,9 @@ function loadPolicy(root) {
1494
1559
  );
1495
1560
  }
1496
1561
  function writeSection(root, updates) {
1497
- const tomlPath = path5.join(root, "studio.toml");
1498
- const text2 = fs6.readFileSync(tomlPath, "utf-8");
1499
- fs6.writeFileSync(tomlPath, updateSection(text2, "budget", updates), "utf-8");
1562
+ const tomlPath = path6.join(root, "studio.toml");
1563
+ const text2 = fs7.readFileSync(tomlPath, "utf-8");
1564
+ fs7.writeFileSync(tomlPath, updateSection(text2, "budget", updates), "utf-8");
1500
1565
  }
1501
1566
  function setBudgetEnabled(on) {
1502
1567
  return on ? cmdEnable({}) : cmdDisable(void 0);
@@ -1543,16 +1608,16 @@ function cmdShow3(projectRoot) {
1543
1608
  return 0;
1544
1609
  }
1545
1610
  function printSpendLedger(root) {
1546
- const ledgerPath = path5.join(root, ".studio", "spend-ledger.json");
1611
+ const ledgerPath = path6.join(root, ".studio", "spend-ledger.json");
1547
1612
  printOut("");
1548
1613
  printOut("spend ledger (.studio/spend-ledger.json):");
1549
- if (!fs6.existsSync(ledgerPath)) {
1614
+ if (!fs7.existsSync(ledgerPath)) {
1550
1615
  printOut(" (no ledger yet)");
1551
1616
  return;
1552
1617
  }
1553
1618
  let entries;
1554
1619
  try {
1555
- const raw = JSON.parse(fs6.readFileSync(ledgerPath, "utf-8"));
1620
+ const raw = JSON.parse(fs7.readFileSync(ledgerPath, "utf-8"));
1556
1621
  entries = Array.isArray(raw.entries) ? raw.entries : [];
1557
1622
  } catch (exc) {
1558
1623
  printOut(
@@ -1643,8 +1708,8 @@ function cmdDisable(projectRoot) {
1643
1708
  }
1644
1709
 
1645
1710
  // src/cli/bundle.ts
1646
- import * as fs8 from "fs";
1647
- import * as path7 from "path";
1711
+ import * as fs9 from "fs";
1712
+ import * as path8 from "path";
1648
1713
  import {
1649
1714
  envLocalPath as envLocalPath4,
1650
1715
  findSubProjectRoot as findSubProjectRoot2,
@@ -1655,29 +1720,29 @@ import * as tar from "tar";
1655
1720
 
1656
1721
  // src/cli/_vendorTarball.ts
1657
1722
  import * as crypto from "crypto";
1658
- import * as fs7 from "fs";
1659
- import * as path6 from "path";
1660
- import { fileURLToPath } from "url";
1723
+ import * as fs8 from "fs";
1724
+ import * as path7 from "path";
1725
+ import { fileURLToPath as fileURLToPath2 } from "url";
1661
1726
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
1662
1727
  var VENDORED_PACKAGES = [
1663
1728
  "@bnbagent/sdk",
1664
1729
  "@bnbagent/studio-runtime"
1665
1730
  ];
1666
1731
  function installedSourceRoot(pkgName) {
1667
- let dir = path6.dirname(fileURLToPath(import.meta.url));
1732
+ let dir = path7.dirname(fileURLToPath2(import.meta.url));
1668
1733
  for (; ; ) {
1669
- const candidate = path6.join(dir, "node_modules", ...pkgName.split("/"));
1670
- const packageJson = path6.join(candidate, "package.json");
1671
- if (fs7.existsSync(packageJson)) {
1734
+ const candidate = path7.join(dir, "node_modules", ...pkgName.split("/"));
1735
+ const packageJson = path7.join(candidate, "package.json");
1736
+ if (fs8.existsSync(packageJson)) {
1672
1737
  try {
1673
- const real = fs7.realpathSync(packageJson);
1674
- const pkg = JSON.parse(fs7.readFileSync(real, "utf-8"));
1675
- return typeof pkg.version === "string" ? { root: path6.dirname(real), version: pkg.version } : null;
1738
+ const real = fs8.realpathSync(packageJson);
1739
+ const pkg = JSON.parse(fs8.readFileSync(real, "utf-8"));
1740
+ return typeof pkg.version === "string" ? { root: path7.dirname(real), version: pkg.version } : null;
1676
1741
  } catch {
1677
1742
  return null;
1678
1743
  }
1679
1744
  }
1680
- const parent = path6.dirname(dir);
1745
+ const parent = path7.dirname(dir);
1681
1746
  if (parent === dir) {
1682
1747
  return null;
1683
1748
  }
@@ -1690,7 +1755,7 @@ function localSourceRoot(pkgName) {
1690
1755
  if (installed === null) {
1691
1756
  return null;
1692
1757
  }
1693
- if (installed.root.split(path6.sep).includes("node_modules")) {
1758
+ if (installed.root.split(path7.sep).includes("node_modules")) {
1694
1759
  return null;
1695
1760
  }
1696
1761
  return installed;
@@ -1706,17 +1771,17 @@ async function publishedOnRegistry(name, version) {
1706
1771
  function contentTag(sourceRoot) {
1707
1772
  const h = crypto.createHash("sha256");
1708
1773
  const files = [];
1709
- const srcDir = path6.join(sourceRoot, "src");
1774
+ const srcDir = path7.join(sourceRoot, "src");
1710
1775
  const walk = (dir) => {
1711
1776
  let names;
1712
1777
  try {
1713
- names = fs7.readdirSync(dir).sort();
1778
+ names = fs8.readdirSync(dir).sort();
1714
1779
  } catch {
1715
1780
  return;
1716
1781
  }
1717
1782
  for (const name of names) {
1718
- const full = path6.join(dir, name);
1719
- const st = fs7.statSync(full);
1783
+ const full = path7.join(dir, name);
1784
+ const st = fs8.statSync(full);
1720
1785
  if (st.isDirectory()) {
1721
1786
  walk(full);
1722
1787
  } else if (st.isFile()) {
@@ -1725,20 +1790,20 @@ function contentTag(sourceRoot) {
1725
1790
  }
1726
1791
  };
1727
1792
  walk(srcDir);
1728
- const pkgJson = path6.join(sourceRoot, "package.json");
1729
- if (fs7.existsSync(pkgJson)) {
1793
+ const pkgJson = path7.join(sourceRoot, "package.json");
1794
+ if (fs8.existsSync(pkgJson)) {
1730
1795
  files.push(pkgJson);
1731
1796
  }
1732
1797
  for (const f of files) {
1733
- h.update(path6.relative(sourceRoot, f));
1734
- h.update(fs7.readFileSync(f));
1798
+ h.update(path7.relative(sourceRoot, f));
1799
+ h.update(fs8.readFileSync(f));
1735
1800
  }
1736
1801
  return h.digest("hex").slice(0, 8);
1737
1802
  }
1738
1803
  function readManifest(vendorDir) {
1739
1804
  try {
1740
1805
  const data = JSON.parse(
1741
- fs7.readFileSync(path6.join(vendorDir, MANIFEST_NAME), "utf-8")
1806
+ fs8.readFileSync(path7.join(vendorDir, MANIFEST_NAME), "utf-8")
1742
1807
  );
1743
1808
  return data !== null && typeof data === "object" ? data : {};
1744
1809
  } catch {
@@ -1746,8 +1811,8 @@ function readManifest(vendorDir) {
1746
1811
  }
1747
1812
  }
1748
1813
  function writeManifest(vendorDir, manifest) {
1749
- fs7.writeFileSync(
1750
- path6.join(vendorDir, MANIFEST_NAME),
1814
+ fs8.writeFileSync(
1815
+ path7.join(vendorDir, MANIFEST_NAME),
1751
1816
  `${JSON.stringify(manifest, null, 2)}
1752
1817
  `
1753
1818
  );
@@ -1756,26 +1821,26 @@ function tarballPrefix(pkgName) {
1756
1821
  return `${pkgName.replace(/^@/, "").replace(/\//g, "-")}-`;
1757
1822
  }
1758
1823
  function sha256File(p) {
1759
- return crypto.createHash("sha256").update(fs7.readFileSync(p)).digest("hex");
1824
+ return crypto.createHash("sha256").update(fs8.readFileSync(p)).digest("hex");
1760
1825
  }
1761
1826
  function rewriteDepToTarball(agentDir, pkgName, tarballName) {
1762
- const pkgJsonPath = path6.join(agentDir, "package.json");
1763
- if (!fs7.existsSync(pkgJsonPath)) {
1827
+ const pkgJsonPath = path7.join(agentDir, "package.json");
1828
+ if (!fs8.existsSync(pkgJsonPath)) {
1764
1829
  return;
1765
1830
  }
1766
- const pkg = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
1831
+ const pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
1767
1832
  if (!pkg.dependencies || !(pkgName in pkg.dependencies)) {
1768
1833
  return;
1769
1834
  }
1770
1835
  pkg.dependencies[pkgName] = `file:vendor/${tarballName}`;
1771
- fs7.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}
1836
+ fs8.writeFileSync(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}
1772
1837
  `);
1773
1838
  }
1774
1839
  async function vendorLocalTarballs(agentDir, opts = {}) {
1775
1840
  const packages = opts.packages ?? VENDORED_PACKAGES;
1776
1841
  const resolveLocal = opts.resolveLocal ?? localSourceRoot;
1777
1842
  const required = new Set(opts.requiredPackages ?? []);
1778
- const vendorDir = path6.join(agentDir, "vendor");
1843
+ const vendorDir = path7.join(agentDir, "vendor");
1779
1844
  const vendored = [];
1780
1845
  for (const pkgName of packages) {
1781
1846
  const local = resolveLocal(pkgName);
@@ -1785,19 +1850,19 @@ async function vendorLocalTarballs(agentDir, opts = {}) {
1785
1850
  if (!opts.force && await publishedOnRegistry(pkgName, local.version)) {
1786
1851
  continue;
1787
1852
  }
1788
- fs7.mkdirSync(vendorDir, { recursive: true });
1853
+ fs8.mkdirSync(vendorDir, { recursive: true });
1789
1854
  const manifest = readManifest(vendorDir);
1790
1855
  const tag = contentTag(local.root);
1791
1856
  const prior = manifest[pkgName];
1792
- if (prior !== void 0 && prior.sourceTag === tag && fs7.existsSync(path6.join(vendorDir, prior.tarball))) {
1857
+ if (prior !== void 0 && prior.sourceTag === tag && fs8.existsSync(path7.join(vendorDir, prior.tarball))) {
1793
1858
  rewriteDepToTarball(agentDir, pkgName, prior.tarball);
1794
1859
  vendored.push(pkgName);
1795
1860
  continue;
1796
1861
  }
1797
1862
  const prefix = tarballPrefix(pkgName);
1798
- for (const name of fs7.readdirSync(vendorDir)) {
1863
+ for (const name of fs8.readdirSync(vendorDir)) {
1799
1864
  if (name.startsWith(prefix) && name.endsWith(".tgz")) {
1800
- fs7.rmSync(path6.join(vendorDir, name), { force: true });
1865
+ fs8.rmSync(path7.join(vendorDir, name), { force: true });
1801
1866
  }
1802
1867
  }
1803
1868
  const result = await runCapture(
@@ -1816,8 +1881,8 @@ ${result.stderr.trim()}` : ""}`;
1816
1881
  }
1817
1882
  const lines = result.stdout.split("\n").filter((l) => l.trim());
1818
1883
  const packed = lines[lines.length - 1]?.trim();
1819
- const tarballPath = packed && fs7.existsSync(packed) ? packed : packed ? path6.join(vendorDir, path6.basename(packed)) : null;
1820
- if (!tarballPath || !fs7.existsSync(tarballPath)) {
1884
+ const tarballPath = packed && fs8.existsSync(packed) ? packed : packed ? path7.join(vendorDir, path7.basename(packed)) : null;
1885
+ if (!tarballPath || !fs8.existsSync(tarballPath)) {
1821
1886
  const message = `pnpm pack for ${pkgName} reported no tarball`;
1822
1887
  if (required.has(pkgName)) {
1823
1888
  throw new Error(message);
@@ -1825,7 +1890,7 @@ ${result.stderr.trim()}` : ""}`;
1825
1890
  printErr(`warning: ${message}; skipping.`);
1826
1891
  continue;
1827
1892
  }
1828
- const tarballName = path6.basename(tarballPath);
1893
+ const tarballName = path7.basename(tarballPath);
1829
1894
  manifest[pkgName] = {
1830
1895
  version: local.version,
1831
1896
  sha256: sha256File(tarballPath),
@@ -1860,20 +1925,20 @@ async function provisionInstall(workspaceRoot) {
1860
1925
  return true;
1861
1926
  }
1862
1927
  function applyWorkspaceVendorOverrides(workspaceRoot, agentDir) {
1863
- const manifest = readManifest(path6.join(agentDir, "vendor"));
1928
+ const manifest = readManifest(path7.join(agentDir, "vendor"));
1864
1929
  const entries = Object.entries(manifest);
1865
1930
  if (entries.length === 0) {
1866
1931
  return;
1867
1932
  }
1868
- const workspacePath = path6.join(workspaceRoot, "pnpm-workspace.yaml");
1933
+ const workspacePath = path7.join(workspaceRoot, "pnpm-workspace.yaml");
1869
1934
  const workspaceDoc = parseYaml(
1870
- fs7.existsSync(workspacePath) ? fs7.readFileSync(workspacePath, "utf-8") : "packages:\n - app/agent\n"
1935
+ fs8.existsSync(workspacePath) ? fs8.readFileSync(workspacePath, "utf-8") : "packages:\n - app/agent\n"
1871
1936
  );
1872
1937
  const workspace = workspaceDoc ?? {};
1873
1938
  const existingOverrides = workspace.overrides !== null && typeof workspace.overrides === "object" && !Array.isArray(workspace.overrides) ? workspace.overrides : {};
1874
- const pkgPath = path6.join(workspaceRoot, "package.json");
1875
- const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
1876
- const relVendor = path6.relative(workspaceRoot, path6.join(agentDir, "vendor")).split(path6.sep).join("/");
1939
+ const pkgPath = path7.join(workspaceRoot, "package.json");
1940
+ const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
1941
+ const relVendor = path7.relative(workspaceRoot, path7.join(agentDir, "vendor")).split(path7.sep).join("/");
1877
1942
  const overrides = {
1878
1943
  ...existingOverrides,
1879
1944
  ...pkg.pnpm?.overrides ?? {}
@@ -1882,10 +1947,10 @@ function applyWorkspaceVendorOverrides(workspaceRoot, agentDir) {
1882
1947
  overrides[name] = `file:${relVendor}/${entry.tarball}`;
1883
1948
  }
1884
1949
  workspace.overrides = overrides;
1885
- fs7.writeFileSync(workspacePath, stringifyYaml(workspace));
1886
- const agentWorkspacePath = path6.join(agentDir, "pnpm-workspace.yaml");
1950
+ fs8.writeFileSync(workspacePath, stringifyYaml(workspace));
1951
+ const agentWorkspacePath = path7.join(agentDir, "pnpm-workspace.yaml");
1887
1952
  const agentWorkspaceDoc = parseYaml(
1888
- fs7.existsSync(agentWorkspacePath) ? fs7.readFileSync(agentWorkspacePath, "utf-8") : "packages:\n - .\nallowBuilds:\n esbuild: true\n"
1953
+ fs8.existsSync(agentWorkspacePath) ? fs8.readFileSync(agentWorkspacePath, "utf-8") : "packages:\n - .\nallowBuilds:\n esbuild: true\n"
1889
1954
  );
1890
1955
  const agentWorkspace = agentWorkspaceDoc ?? {};
1891
1956
  const agentOverrides = agentWorkspace.overrides !== null && typeof agentWorkspace.overrides === "object" && !Array.isArray(agentWorkspace.overrides) ? agentWorkspace.overrides : {};
@@ -1893,9 +1958,9 @@ function applyWorkspaceVendorOverrides(workspaceRoot, agentDir) {
1893
1958
  agentOverrides[name] = `file:vendor/${entry.tarball}`;
1894
1959
  }
1895
1960
  agentWorkspace.overrides = agentOverrides;
1896
- fs7.writeFileSync(agentWorkspacePath, stringifyYaml(agentWorkspace));
1961
+ fs8.writeFileSync(agentWorkspacePath, stringifyYaml(agentWorkspace));
1897
1962
  pkg.pnpm = { ...pkg.pnpm ?? {}, overrides };
1898
- fs7.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
1963
+ fs8.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
1899
1964
  `);
1900
1965
  }
1901
1966
 
@@ -1930,7 +1995,7 @@ function registerBundle(program) {
1930
1995
  act(async (opts) => {
1931
1996
  try {
1932
1997
  const result = await createBundle(opts);
1933
- const sizeKb = fs8.statSync(result.archivePath).size / 1024;
1998
+ const sizeKb = fs9.statSync(result.archivePath).size / 1024;
1934
1999
  printOut("");
1935
2000
  printOut(
1936
2001
  `\u2713 bundle ready: ${result.archivePath} (${sizeKb.toFixed(1)} KB)`
@@ -1952,7 +2017,7 @@ function registerBundle(program) {
1952
2017
  );
1953
2018
  }
1954
2019
  async function createBundle(opts = {}) {
1955
- const start = path7.resolve(opts.projectRoot ?? process.cwd());
2020
+ const start = path8.resolve(opts.projectRoot ?? process.cwd());
1956
2021
  const agentRoot2 = resolveAgentRoot(start);
1957
2022
  if (agentRoot2 === null) {
1958
2023
  throw new Error(
@@ -1962,24 +2027,24 @@ async function createBundle(opts = {}) {
1962
2027
  const workspaceRoot = trueWorkspaceRoot(agentRoot2);
1963
2028
  const projectName2 = readProjectName(agentRoot2);
1964
2029
  const safeName = projectName2.replace(/[^A-Za-z0-9._-]+/g, "-");
1965
- const outputDir = path7.resolve(
1966
- opts.output ?? path7.join(workspaceRoot, "dist")
2030
+ const outputDir = path8.resolve(
2031
+ opts.output ?? path8.join(workspaceRoot, "dist")
1967
2032
  );
1968
- fs8.mkdirSync(outputDir, { recursive: true });
2033
+ fs9.mkdirSync(outputDir, { recursive: true });
1969
2034
  const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1970
2035
  const archiveBase = `${safeName}-bundle-${stamp}`;
1971
- const stagingRoot = path7.join(outputDir, `.${archiveBase}.staging`);
1972
- const stagedWorkspace = path7.join(stagingRoot, safeName);
2036
+ const stagingRoot = path8.join(outputDir, `.${archiveBase}.staging`);
2037
+ const stagedWorkspace = path8.join(stagingRoot, safeName);
1973
2038
  if (stagedWorkspace === stagingRoot || !inside(stagedWorkspace, stagingRoot)) {
1974
2039
  throw new Error(
1975
2040
  `unsafe project name ${JSON.stringify(projectName2)} escapes the bundle staging directory`
1976
2041
  );
1977
2042
  }
1978
- const agentRel = path7.relative(workspaceRoot, agentRoot2);
1979
- const stagedAgent = path7.join(stagedWorkspace, agentRel);
1980
- const archivePath = path7.join(outputDir, `${archiveBase}.tar.gz`);
1981
- fs8.rmSync(stagingRoot, { recursive: true, force: true });
1982
- fs8.mkdirSync(stagingRoot, { recursive: true });
2043
+ const agentRel = path8.relative(workspaceRoot, agentRoot2);
2044
+ const stagedAgent = path8.join(stagedWorkspace, agentRel);
2045
+ const archivePath = path8.join(outputDir, `${archiveBase}.tar.gz`);
2046
+ fs9.rmSync(stagingRoot, { recursive: true, force: true });
2047
+ fs9.mkdirSync(stagingRoot, { recursive: true });
1983
2048
  try {
1984
2049
  printOut(`\u2192 Staging seller workspace at ${stagedWorkspace}\u2026`);
1985
2050
  copyWorkspace(workspaceRoot, stagedWorkspace, outputDir);
@@ -2018,26 +2083,26 @@ async function createBundle(opts = {}) {
2018
2083
  [safeName]
2019
2084
  );
2020
2085
  } finally {
2021
- fs8.rmSync(stagingRoot, { recursive: true, force: true });
2086
+ fs9.rmSync(stagingRoot, { recursive: true, force: true });
2022
2087
  }
2023
2088
  return { archivePath, projectName: projectName2 };
2024
2089
  }
2025
2090
  function resolveAgentRoot(start) {
2026
2091
  const found = findSubProjectRoot2("agent", start);
2027
- if (found !== null && fs8.existsSync(path7.join(found, "studio.toml"))) {
2092
+ if (found !== null && fs9.existsSync(path8.join(found, "studio.toml"))) {
2028
2093
  return found;
2029
2094
  }
2030
- return fs8.existsSync(path7.join(start, "studio.toml")) ? start : null;
2095
+ return fs9.existsSync(path8.join(start, "studio.toml")) ? start : null;
2031
2096
  }
2032
2097
  function trueWorkspaceRoot(agentRoot2) {
2033
2098
  const found = findWorkspaceRoot2(agentRoot2);
2034
2099
  if (found === null) {
2035
2100
  return agentRoot2;
2036
2101
  }
2037
- return path7.basename(found) === "app" ? path7.dirname(found) : found;
2102
+ return path8.basename(found) === "app" ? path8.dirname(found) : found;
2038
2103
  }
2039
2104
  function readProjectName(agentRoot2) {
2040
- const cfg = loadStudioToml2(path7.join(agentRoot2, "studio.toml"));
2105
+ const cfg = loadStudioToml2(path8.join(agentRoot2, "studio.toml"));
2041
2106
  const project = cfg.project;
2042
2107
  const name = project !== null && typeof project === "object" && !Array.isArray(project) ? project.name : null;
2043
2108
  if (!name) {
@@ -2050,58 +2115,58 @@ function excludedName(name) {
2050
2115
  return EXCLUDED_NAMES.has(lowerName) || CREDENTIAL_FILE_NAMES.has(lowerName) || lowerName.startsWith(".env") || lowerName.endsWith(".egg-info") || lowerName.startsWith(".venv-");
2051
2116
  }
2052
2117
  function inside(child, parent) {
2053
- const rel = path7.relative(parent, child);
2054
- return rel === "" || !rel.startsWith("..") && !path7.isAbsolute(rel);
2118
+ const rel = path8.relative(parent, child);
2119
+ return rel === "" || !rel.startsWith("..") && !path8.isAbsolute(rel);
2055
2120
  }
2056
2121
  function copyWorkspace(sourceRoot, destinationRoot, outputDir) {
2057
- const source = path7.resolve(sourceRoot);
2058
- const excludedOutput = outputDir ? path7.resolve(outputDir) : null;
2122
+ const source = path8.resolve(sourceRoot);
2123
+ const excludedOutput = outputDir ? path8.resolve(outputDir) : null;
2059
2124
  const copy = (src, dst) => {
2060
2125
  if (excludedOutput !== null && inside(src, excludedOutput)) {
2061
2126
  return;
2062
2127
  }
2063
- const name = path7.basename(src);
2128
+ const name = path8.basename(src);
2064
2129
  if (src !== source && excludedName(name)) {
2065
2130
  return;
2066
2131
  }
2067
- const stat = fs8.lstatSync(src);
2132
+ const stat = fs9.lstatSync(src);
2068
2133
  if (stat.isSymbolicLink()) {
2069
- const link = fs8.readlinkSync(src);
2070
- const lexicalTarget = path7.resolve(path7.dirname(src), link);
2134
+ const link = fs9.readlinkSync(src);
2135
+ const lexicalTarget = path8.resolve(path8.dirname(src), link);
2071
2136
  let resolvedTarget = lexicalTarget;
2072
2137
  try {
2073
- resolvedTarget = fs8.realpathSync(lexicalTarget);
2138
+ resolvedTarget = fs9.realpathSync(lexicalTarget);
2074
2139
  } catch {
2075
2140
  }
2076
2141
  if (!inside(resolvedTarget, source)) {
2077
2142
  throw new Error(
2078
- `refusing to bundle symlink ${path7.relative(source, src)} \u2192 ${link}: its target escapes the project tree (possible secret leak).`
2143
+ `refusing to bundle symlink ${path8.relative(source, src)} \u2192 ${link}: its target escapes the project tree (possible secret leak).`
2079
2144
  );
2080
2145
  }
2081
- fs8.mkdirSync(path7.dirname(dst), { recursive: true });
2082
- fs8.symlinkSync(link, dst);
2146
+ fs9.mkdirSync(path8.dirname(dst), { recursive: true });
2147
+ fs9.symlinkSync(link, dst);
2083
2148
  return;
2084
2149
  }
2085
2150
  if (stat.isDirectory()) {
2086
- fs8.mkdirSync(dst, { recursive: true, mode: stat.mode & 511 });
2087
- for (const child of fs8.readdirSync(src).sort()) {
2088
- copy(path7.join(src, child), path7.join(dst, child));
2151
+ fs9.mkdirSync(dst, { recursive: true, mode: stat.mode & 511 });
2152
+ for (const child of fs9.readdirSync(src).sort()) {
2153
+ copy(path8.join(src, child), path8.join(dst, child));
2089
2154
  }
2090
2155
  return;
2091
2156
  }
2092
2157
  if (stat.isFile()) {
2093
- fs8.mkdirSync(path7.dirname(dst), { recursive: true });
2094
- fs8.copyFileSync(src, dst);
2095
- fs8.chmodSync(dst, stat.mode & 511);
2158
+ fs9.mkdirSync(path8.dirname(dst), { recursive: true });
2159
+ fs9.copyFileSync(src, dst);
2160
+ fs9.chmodSync(dst, stat.mode & 511);
2096
2161
  }
2097
2162
  };
2098
2163
  copy(source, destinationRoot);
2099
2164
  }
2100
2165
  function writeEnvExample(agentRoot2, stagedWorkspace) {
2101
2166
  const sourceEnv = envLocalPath4(agentRoot2);
2102
- const targetDir = path7.join(stagedWorkspace, ".studio");
2103
- const target = path7.join(targetDir, ".env.local.example");
2104
- fs8.mkdirSync(targetDir, { recursive: true, mode: 448 });
2167
+ const targetDir = path8.join(stagedWorkspace, ".studio");
2168
+ const target = path8.join(targetDir, ".env.local.example");
2169
+ fs9.mkdirSync(targetDir, { recursive: true, mode: 448 });
2105
2170
  const header = [
2106
2171
  "# Copy to .studio/.env.local and fill in values.",
2107
2172
  "# Generated by `bag bundle`; secret values were stripped.",
@@ -2109,7 +2174,7 @@ function writeEnvExample(agentRoot2, stagedWorkspace) {
2109
2174
  ];
2110
2175
  let lines;
2111
2176
  try {
2112
- lines = fs8.readFileSync(sourceEnv, "utf-8").split(/\r?\n/);
2177
+ lines = fs9.readFileSync(sourceEnv, "utf-8").split(/\r?\n/);
2113
2178
  } catch {
2114
2179
  lines = [
2115
2180
  "WALLET_PASSWORD=",
@@ -2127,29 +2192,29 @@ function writeEnvExample(agentRoot2, stagedWorkspace) {
2127
2192
  const match = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line);
2128
2193
  return match ? `${match[1]}=` : "# omitted unrecognized dotenv entry";
2129
2194
  });
2130
- fs8.writeFileSync(target, `${[...header, ...stripped].join("\n")}
2195
+ fs9.writeFileSync(target, `${[...header, ...stripped].join("\n")}
2131
2196
  `, {
2132
2197
  mode: 384
2133
2198
  });
2134
2199
  }
2135
2200
  function findStagedLeak(stagedWorkspace) {
2136
- const root = path7.resolve(stagedWorkspace);
2201
+ const root = path8.resolve(stagedWorkspace);
2137
2202
  const walk = (dir) => {
2138
- for (const name of fs8.readdirSync(dir).sort()) {
2139
- const full = path7.join(dir, name);
2140
- const rel = path7.relative(root, full);
2141
- const stat = fs8.lstatSync(full);
2203
+ for (const name of fs9.readdirSync(dir).sort()) {
2204
+ const full = path8.join(dir, name);
2205
+ const rel = path8.relative(root, full);
2206
+ const stat = fs9.lstatSync(full);
2142
2207
  const lowerName = name.toLowerCase();
2143
2208
  if (stat.isSymbolicLink()) {
2144
- const link = fs8.readlinkSync(full);
2145
- const target = path7.resolve(path7.dirname(full), link);
2209
+ const link = fs9.readlinkSync(full);
2210
+ const target = path8.resolve(path8.dirname(full), link);
2146
2211
  if (!inside(target, root)) {
2147
2212
  return `escaping symlink ${rel} \u2192 ${link}`;
2148
2213
  }
2149
2214
  continue;
2150
2215
  }
2151
2216
  if (stat.isDirectory()) {
2152
- if (lowerName === "wallets" && path7.basename(path7.dirname(full)).toLowerCase() === ".studio") {
2217
+ if (lowerName === "wallets" && path8.basename(path8.dirname(full)).toLowerCase() === ".studio") {
2153
2218
  return `wallet directory ${rel}`;
2154
2219
  }
2155
2220
  const nested = walk(full);
@@ -2167,7 +2232,7 @@ function findStagedLeak(stagedWorkspace) {
2167
2232
  "# omitted source comment",
2168
2233
  "# omitted unrecognized dotenv entry"
2169
2234
  ]);
2170
- const unsafeExample = fs8.readFileSync(full, "utf-8").split(/\r?\n/u).some((line) => {
2235
+ const unsafeExample = fs9.readFileSync(full, "utf-8").split(/\r?\n/u).some((line) => {
2171
2236
  if (!line.trim() || safeFixedLines.has(line)) return false;
2172
2237
  return !/^#?\s*[A-Za-z_][A-Za-z0-9_]*=$/u.test(line);
2173
2238
  });
@@ -2218,12 +2283,12 @@ function writeInstallMd(stagedWorkspace, projectName2) {
2218
2283
  "- `node_modules/`, build outputs, caches, and repository history",
2219
2284
  ""
2220
2285
  ];
2221
- fs8.writeFileSync(path7.join(stagedWorkspace, "INSTALL.md"), lines.join("\n"));
2286
+ fs9.writeFileSync(path8.join(stagedWorkspace, "INSTALL.md"), lines.join("\n"));
2222
2287
  }
2223
2288
 
2224
2289
  // src/cli/config.ts
2225
- import * as fs9 from "fs";
2226
- import * as path8 from "path";
2290
+ import * as fs10 from "fs";
2291
+ import * as path9 from "path";
2227
2292
  import { NegotiationHandler } from "@bnbagent/sdk/erc8183";
2228
2293
  import { Option } from "commander";
2229
2294
  import { parse as parse4 } from "smol-toml";
@@ -2489,8 +2554,8 @@ function cmdShow4(asJson, projectRoot) {
2489
2554
  if (root === null) {
2490
2555
  return 2;
2491
2556
  }
2492
- const tomlPath = path8.join(root, "studio.toml");
2493
- const text2 = fs9.readFileSync(tomlPath, "utf-8");
2557
+ const tomlPath = path9.join(root, "studio.toml");
2558
+ const text2 = fs10.readFileSync(tomlPath, "utf-8");
2494
2559
  if (asJson) {
2495
2560
  printOut(sortedJson(parse4(text2)));
2496
2561
  } else {
@@ -2506,7 +2571,7 @@ function cmdGet(key, projectRoot) {
2506
2571
  if (root === null) {
2507
2572
  return 2;
2508
2573
  }
2509
- const doc = parse4(fs9.readFileSync(path8.join(root, "studio.toml"), "utf-8"));
2574
+ const doc = parse4(fs10.readFileSync(path9.join(root, "studio.toml"), "utf-8"));
2510
2575
  let val;
2511
2576
  try {
2512
2577
  val = navigate(doc, splitKey(key));
@@ -2528,8 +2593,8 @@ async function cmdSet(key, rawValue, typeFlag, projectRoot) {
2528
2593
  if (root === null) {
2529
2594
  return 2;
2530
2595
  }
2531
- const tomlPath = path8.join(root, "studio.toml");
2532
- const text2 = fs9.readFileSync(tomlPath, "utf-8");
2596
+ const tomlPath = path9.join(root, "studio.toml");
2597
+ const text2 = fs10.readFileSync(tomlPath, "utf-8");
2533
2598
  let parts;
2534
2599
  try {
2535
2600
  parts = splitKey(key);
@@ -2550,7 +2615,7 @@ async function cmdSet(key, rawValue, typeFlag, projectRoot) {
2550
2615
  return 2;
2551
2616
  }
2552
2617
  const updatedText = setDottedKey(text2, parts, value);
2553
- fs9.writeFileSync(tomlPath, updatedText, "utf-8");
2618
+ fs10.writeFileSync(tomlPath, updatedText, "utf-8");
2554
2619
  printOut(`set ${key} = ${JSON.stringify(plainValue(value))}`);
2555
2620
  if (parts.length === 3 && parts[0] === "payments" && parts[1] === "erc8183" && parts[2] === "price") {
2556
2621
  const updated = parse4(updatedText);
@@ -2623,7 +2688,7 @@ function cmdListKeys(projectRoot) {
2623
2688
  if (root === null) {
2624
2689
  return 2;
2625
2690
  }
2626
- const doc = parse4(fs9.readFileSync(path8.join(root, "studio.toml"), "utf-8"));
2691
+ const doc = parse4(fs10.readFileSync(path9.join(root, "studio.toml"), "utf-8"));
2627
2692
  const leaves = iterLeaves(doc, []);
2628
2693
  leaves.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
2629
2694
  for (const [k, v] of leaves) {
@@ -2645,8 +2710,8 @@ import { pieverseKeyHash as pieverseKeyHash3 } from "@bnbagent/studio-runtime/ll
2645
2710
  import { Option as Option4 } from "commander";
2646
2711
 
2647
2712
  // src/cli/_agentcoreAccess.ts
2648
- import * as fs10 from "fs";
2649
- import * as path9 from "path";
2713
+ import * as fs11 from "fs";
2714
+ import * as path10 from "path";
2650
2715
  import {
2651
2716
  envLocalPath as envLocalPath5,
2652
2717
  findWorkspaceRoot as findWorkspaceRoot3,
@@ -2655,7 +2720,7 @@ import {
2655
2720
  var GUIDE_URL = "https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/agentcore-a2a-access.md";
2656
2721
  function isFile2(p) {
2657
2722
  try {
2658
- return fs10.statSync(p).isFile();
2723
+ return fs11.statSync(p).isFile();
2659
2724
  } catch {
2660
2725
  return false;
2661
2726
  }
@@ -2670,13 +2735,13 @@ function envValue(entries, key) {
2670
2735
  return null;
2671
2736
  }
2672
2737
  function descriptorEnv(workspaceRoot) {
2673
- const descriptor = path9.join(workspaceRoot, "agentcore", "agentcore.json");
2738
+ const descriptor = path10.join(workspaceRoot, "agentcore", "agentcore.json");
2674
2739
  if (!isFile2(descriptor)) {
2675
2740
  return [];
2676
2741
  }
2677
2742
  let data;
2678
2743
  try {
2679
- data = JSON.parse(fs10.readFileSync(descriptor, "utf-8"));
2744
+ data = JSON.parse(fs11.readFileSync(descriptor, "utf-8"));
2680
2745
  } catch {
2681
2746
  return [];
2682
2747
  }
@@ -2695,8 +2760,8 @@ function descriptorEnv(workspaceRoot) {
2695
2760
  return Array.isArray(env) ? env : [];
2696
2761
  }
2697
2762
  function agentcoreProjectRoot(workspaceRoot) {
2698
- for (const candidate of [path9.dirname(workspaceRoot), workspaceRoot]) {
2699
- if (isFile2(path9.join(candidate, "agentcore", "agentcore.json"))) {
2763
+ for (const candidate of [path10.dirname(workspaceRoot), workspaceRoot]) {
2764
+ if (isFile2(path10.join(candidate, "agentcore", "agentcore.json"))) {
2700
2765
  return candidate;
2701
2766
  }
2702
2767
  }
@@ -2708,7 +2773,7 @@ function dotenvValue(filePath, key) {
2708
2773
  }
2709
2774
  let lines;
2710
2775
  try {
2711
- lines = fs10.readFileSync(filePath, "utf-8").split(/\r?\n/);
2776
+ lines = fs11.readFileSync(filePath, "utf-8").split(/\r?\n/);
2712
2777
  } catch {
2713
2778
  return null;
2714
2779
  }
@@ -2741,7 +2806,7 @@ function oauthFacts(workspaceRoot, agentRoot2) {
2741
2806
  function accessSummaryForAgentcore(agentRoot2, opts = {}) {
2742
2807
  let data;
2743
2808
  try {
2744
- data = loadStudioToml3(path9.join(agentRoot2, "studio.toml"));
2809
+ data = loadStudioToml3(path10.join(agentRoot2, "studio.toml"));
2745
2810
  } catch {
2746
2811
  return null;
2747
2812
  }
@@ -2774,8 +2839,8 @@ import {
2774
2839
  } from "@bnbagent/studio-runtime/config";
2775
2840
 
2776
2841
  // src/cli/_deploy/checks/_wallet.ts
2777
- import * as fs11 from "fs";
2778
- import * as path10 from "path";
2842
+ import * as fs12 from "fs";
2843
+ import * as path11 from "path";
2779
2844
  import {
2780
2845
  findSubProjectRoot as findSubProjectRoot3,
2781
2846
  loadStudioToml as loadStudioToml4
@@ -2882,16 +2947,16 @@ async function checkUBalance(walletAddress, neededUsd, networkName) {
2882
2947
 
2883
2948
  // src/cli/_deploy/checks/_wallet.ts
2884
2949
  function agentRootOf(root) {
2885
- return findSubProjectRoot3("agent", root) ?? path10.join(root, "app", "agent");
2950
+ return findSubProjectRoot3("agent", root) ?? path11.join(root, "app", "agent");
2886
2951
  }
2887
2952
  function tableOf2(data, key) {
2888
2953
  const v = data[key];
2889
2954
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
2890
2955
  }
2891
2956
  function loadAgentToml(root) {
2892
- const p = path10.join(agentRootOf(root), "studio.toml");
2957
+ const p = path11.join(agentRootOf(root), "studio.toml");
2893
2958
  try {
2894
- if (!fs11.statSync(p).isFile()) {
2959
+ if (!fs12.statSync(p).isFile()) {
2895
2960
  return {};
2896
2961
  }
2897
2962
  } catch {
@@ -2905,7 +2970,7 @@ function loadAgentToml(root) {
2905
2970
  }
2906
2971
  function keystoreJsonPresent(dir) {
2907
2972
  try {
2908
- return fs11.statSync(dir).isDirectory() && fs11.readdirSync(dir).some((n) => n.endsWith(".json"));
2973
+ return fs12.statSync(dir).isDirectory() && fs12.readdirSync(dir).some((n) => n.endsWith(".json"));
2909
2974
  } catch {
2910
2975
  return false;
2911
2976
  }
@@ -2926,7 +2991,7 @@ function canBuildWallet(root, data) {
2926
2991
  return false;
2927
2992
  }
2928
2993
  const rel = String(walletCfg.keystore_dir ?? ".studio/wallets");
2929
- const keystoreDir = path10.isAbsolute(rel) ? rel : path10.join(agentRootOf(root), rel);
2994
+ const keystoreDir = path11.isAbsolute(rel) ? rel : path11.join(agentRootOf(root), rel);
2930
2995
  return keystoreJsonPresent(keystoreDir);
2931
2996
  }
2932
2997
  function walletAddressForChecks(root, data) {
@@ -3100,8 +3165,8 @@ import { writePrivate as writePrivate2 } from "@bnbagent/studio-runtime/secretWr
3100
3165
  import { Option as Option3 } from "commander";
3101
3166
 
3102
3167
  // src/cli/_migrations.ts
3103
- import * as fs12 from "fs";
3104
- import * as path11 from "path";
3168
+ import * as fs13 from "fs";
3169
+ import * as path12 from "path";
3105
3170
  import {
3106
3171
  envLocalPath as envLocalPath7,
3107
3172
  findSubProjectRoot as findSubProjectRoot5,
@@ -3109,59 +3174,59 @@ import {
3109
3174
  } from "@bnbagent/studio-runtime/config";
3110
3175
  function isFile3(p) {
3111
3176
  try {
3112
- return fs12.statSync(p).isFile();
3177
+ return fs13.statSync(p).isFile();
3113
3178
  } catch {
3114
3179
  return false;
3115
3180
  }
3116
3181
  }
3117
3182
  function isDir2(p) {
3118
3183
  try {
3119
- return fs12.statSync(p).isDirectory();
3184
+ return fs13.statSync(p).isDirectory();
3120
3185
  } catch {
3121
3186
  return false;
3122
3187
  }
3123
3188
  }
3124
3189
  function realpathOr(p) {
3125
3190
  try {
3126
- return fs12.realpathSync(p);
3191
+ return fs13.realpathSync(p);
3127
3192
  } catch {
3128
- return path11.resolve(p);
3193
+ return path12.resolve(p);
3129
3194
  }
3130
3195
  }
3131
3196
  function keystoreJsonFiles(dir) {
3132
3197
  if (!isDir2(dir)) {
3133
3198
  return [];
3134
3199
  }
3135
- return fs12.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
3200
+ return fs13.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
3136
3201
  }
3137
3202
  function migrateEnvLocal(start) {
3138
3203
  try {
3139
3204
  const target = envLocalPath7(start);
3140
- const ws = path11.dirname(path11.dirname(target));
3205
+ const ws = path12.dirname(path12.dirname(target));
3141
3206
  const agentRoot2 = findSubProjectRoot5("agent", start);
3142
3207
  const sources = [];
3143
3208
  if (agentRoot2 !== null) {
3144
- sources.push(path11.join(agentRoot2, ".env.local"));
3209
+ sources.push(path12.join(agentRoot2, ".env.local"));
3145
3210
  }
3146
- sources.push(path11.join(ws, ".bag-env-stash", ".env.local"));
3211
+ sources.push(path12.join(ws, ".bag-env-stash", ".env.local"));
3147
3212
  for (const src of sources) {
3148
- if (!isFile3(src) || path11.resolve(src) === path11.resolve(target)) {
3213
+ if (!isFile3(src) || path12.resolve(src) === path12.resolve(target)) {
3149
3214
  continue;
3150
3215
  }
3151
- if (fs12.existsSync(target)) {
3216
+ if (fs13.existsSync(target)) {
3152
3217
  printErr(
3153
3218
  `note: both ${src} and ${target} exist; left ${src} untouched. Secrets now live in .studio/.env.local \u2014 reconcile and remove the old file.`
3154
3219
  );
3155
3220
  continue;
3156
3221
  }
3157
- fs12.mkdirSync(path11.dirname(target), { recursive: true });
3158
- fs12.renameSync(src, target);
3159
- fs12.chmodSync(target, 384);
3222
+ fs13.mkdirSync(path12.dirname(target), { recursive: true });
3223
+ fs13.renameSync(src, target);
3224
+ fs13.chmodSync(target, 384);
3160
3225
  printErr(
3161
3226
  `note: migrated ${src} -> ${target} (secrets now live outside the deploy codeLocation).`
3162
3227
  );
3163
3228
  }
3164
- fs12.rmSync(path11.join(ws, ".bag-env-stash"), {
3229
+ fs13.rmSync(path12.join(ws, ".bag-env-stash"), {
3165
3230
  recursive: true,
3166
3231
  force: true
3167
3232
  });
@@ -3171,7 +3236,7 @@ function migrateEnvLocal(start) {
3171
3236
  var KEYSTORE_WALLET_KINDS = /* @__PURE__ */ new Set(["evm-local", "altana"]);
3172
3237
  function readWalletKind(agentRoot2) {
3173
3238
  try {
3174
- const wallet = loadStudioToml5(path11.join(agentRoot2, "studio.toml")).wallet;
3239
+ const wallet = loadStudioToml5(path12.join(agentRoot2, "studio.toml")).wallet;
3175
3240
  if (wallet !== null && typeof wallet === "object") {
3176
3241
  const kind = wallet.kind;
3177
3242
  if (typeof kind === "string" && kind.trim()) {
@@ -3185,7 +3250,7 @@ function readWalletKind(agentRoot2) {
3185
3250
  function resolveKeystoreDir(agentRoot2) {
3186
3251
  let rel = ".studio/wallets";
3187
3252
  try {
3188
- const data = loadStudioToml5(path11.join(agentRoot2, "studio.toml"));
3253
+ const data = loadStudioToml5(path12.join(agentRoot2, "studio.toml"));
3189
3254
  const wallet = data.wallet;
3190
3255
  if (wallet !== null && typeof wallet === "object") {
3191
3256
  const v = wallet.keystore_dir;
@@ -3195,24 +3260,24 @@ function resolveKeystoreDir(agentRoot2) {
3195
3260
  }
3196
3261
  } catch {
3197
3262
  }
3198
- return path11.isAbsolute(rel) ? rel : path11.join(agentRoot2, rel);
3263
+ return path12.isAbsolute(rel) ? rel : path12.join(agentRoot2, rel);
3199
3264
  }
3200
3265
  function migrateKeystoreOutOfCodelocation(start) {
3201
3266
  const agentRoot2 = findSubProjectRoot5("agent", start);
3202
3267
  if (agentRoot2 === null) {
3203
3268
  return;
3204
3269
  }
3205
- const ws = path11.dirname(path11.dirname(envLocalPath7(start)));
3206
- const target = path11.join(ws, ".studio", "wallets");
3207
- const stash = path11.join(ws, ".bag-keystore-stash");
3270
+ const ws = path12.dirname(path12.dirname(envLocalPath7(start)));
3271
+ const target = path12.join(ws, ".studio", "wallets");
3272
+ const stash = path12.join(ws, ".bag-keystore-stash");
3208
3273
  if (isDir2(stash)) {
3209
- for (const name of fs12.readdirSync(stash).sort()) {
3210
- const sub = path11.join(stash, name);
3274
+ for (const name of fs13.readdirSync(stash).sort()) {
3275
+ const sub = path12.join(stash, name);
3211
3276
  if (isDir2(sub) && keystoreJsonFiles(sub).length > 0) {
3212
3277
  relocateKeys(sub, target, "stashed keystore");
3213
3278
  }
3214
3279
  }
3215
- fs12.rmSync(stash, { recursive: true, force: true });
3280
+ fs13.rmSync(stash, { recursive: true, force: true });
3216
3281
  }
3217
3282
  if (!KEYSTORE_WALLET_KINDS.has(readWalletKind(agentRoot2))) {
3218
3283
  return;
@@ -3220,7 +3285,7 @@ function migrateKeystoreOutOfCodelocation(start) {
3220
3285
  const src = resolveKeystoreDir(agentRoot2);
3221
3286
  const srcReal = realpathOr(src);
3222
3287
  const agentReal = realpathOr(agentRoot2);
3223
- if (srcReal !== agentReal && !srcReal.startsWith(agentReal + path11.sep)) {
3288
+ if (srcReal !== agentReal && !srcReal.startsWith(agentReal + path12.sep)) {
3224
3289
  return;
3225
3290
  }
3226
3291
  if (srcReal === realpathOr(target)) {
@@ -3231,13 +3296,13 @@ function migrateKeystoreOutOfCodelocation(start) {
3231
3296
  return;
3232
3297
  }
3233
3298
  }
3234
- const rel = path11.relative(agentRoot2, target).split(path11.sep).join("/");
3235
- const tomlPath = path11.join(agentRoot2, "studio.toml");
3299
+ const rel = path12.relative(agentRoot2, target).split(path12.sep).join("/");
3300
+ const tomlPath = path12.join(agentRoot2, "studio.toml");
3236
3301
  if (isFile3(tomlPath)) {
3237
- const text2 = fs12.readFileSync(tomlPath, "utf-8");
3302
+ const text2 = fs13.readFileSync(tomlPath, "utf-8");
3238
3303
  const updated = updateSection(text2, "wallet", { keystore_dir: rel });
3239
3304
  if (updated !== text2) {
3240
- fs12.writeFileSync(tomlPath, updated);
3305
+ fs13.writeFileSync(tomlPath, updated);
3241
3306
  printErr(
3242
3307
  `note: updated [wallet].keystore_dir -> ${rel} in studio.toml (keystore now lives at the workspace root, outside the codeLocation).`
3243
3308
  );
@@ -3245,7 +3310,7 @@ function migrateKeystoreOutOfCodelocation(start) {
3245
3310
  }
3246
3311
  }
3247
3312
  function relocateKeys(src, target, label) {
3248
- fs12.mkdirSync(target, { recursive: true });
3313
+ fs13.mkdirSync(target, { recursive: true });
3249
3314
  if (keystoreJsonFiles(target).length > 0) {
3250
3315
  printErr(
3251
3316
  `note: both a ${label} at ${src} and keys at ${target} exist; left ${src} untouched for manual review (never overwritten).`
@@ -3253,15 +3318,15 @@ function relocateKeys(src, target, label) {
3253
3318
  return false;
3254
3319
  }
3255
3320
  try {
3256
- for (const name of fs12.readdirSync(src)) {
3257
- const f = path11.join(src, name);
3258
- if (fs12.statSync(f).isFile()) {
3259
- fs12.copyFileSync(f, path11.join(target, name));
3321
+ for (const name of fs13.readdirSync(src)) {
3322
+ const f = path12.join(src, name);
3323
+ if (fs13.statSync(f).isFile()) {
3324
+ fs13.copyFileSync(f, path12.join(target, name));
3260
3325
  }
3261
3326
  }
3262
3327
  for (const name of keystoreJsonFiles(src)) {
3263
- const a = fs12.readFileSync(path11.join(src, name));
3264
- const b = fs12.readFileSync(path11.join(target, name));
3328
+ const a = fs13.readFileSync(path12.join(src, name));
3329
+ const b = fs13.readFileSync(path12.join(target, name));
3265
3330
  if (!a.equals(b)) {
3266
3331
  throw new Error(`verification mismatch for ${name}`);
3267
3332
  }
@@ -3273,7 +3338,7 @@ function relocateKeys(src, target, label) {
3273
3338
  );
3274
3339
  return false;
3275
3340
  }
3276
- fs12.rmSync(src, { recursive: true, force: true });
3341
+ fs13.rmSync(src, { recursive: true, force: true });
3277
3342
  printErr(
3278
3343
  `note: migrated ${label} ${src} -> ${target} (now outside the deploy codeLocation).`
3279
3344
  );
@@ -3290,8 +3355,8 @@ import { Option as Option2 } from "commander";
3290
3355
  import { parse as parseToml } from "smol-toml";
3291
3356
 
3292
3357
  // src/cli/_deploy/providers.ts
3293
- import * as fs13 from "fs";
3294
- import * as path12 from "path";
3358
+ import * as fs14 from "fs";
3359
+ import * as path13 from "path";
3295
3360
  import {
3296
3361
  findSubProjectRoot as findSubProjectRoot6,
3297
3362
  findWorkspaceRoot as findWorkspaceRoot4,
@@ -3334,8 +3399,8 @@ function text(value) {
3334
3399
  function descriptorName(workspaceRoot) {
3335
3400
  try {
3336
3401
  const data = JSON.parse(
3337
- fs13.readFileSync(
3338
- path12.join(workspaceRoot, "agentcore", "agentcore.json"),
3402
+ fs14.readFileSync(
3403
+ path13.join(workspaceRoot, "agentcore", "agentcore.json"),
3339
3404
  "utf-8"
3340
3405
  )
3341
3406
  );
@@ -3345,16 +3410,16 @@ function descriptorName(workspaceRoot) {
3345
3410
  }
3346
3411
  }
3347
3412
  function discoverRecordedDeployments(root) {
3348
- const workspaceRoot = findWorkspaceRoot4(root) ?? path12.resolve(root);
3413
+ const workspaceRoot = findWorkspaceRoot4(root) ?? path13.resolve(root);
3349
3414
  const agentRoot2 = findSubProjectRoot6("agent", workspaceRoot);
3350
3415
  if (agentRoot2 === null) return [];
3351
3416
  let config;
3352
3417
  try {
3353
- config = loadStudioToml6(path12.join(agentRoot2, "studio.toml"));
3418
+ config = loadStudioToml6(path13.join(agentRoot2, "studio.toml"));
3354
3419
  } catch {
3355
3420
  return [];
3356
3421
  }
3357
- const projectName2 = descriptorName(workspaceRoot) ?? text(tableOf3(config, "project").name) ?? path12.basename(workspaceRoot);
3422
+ const projectName2 = descriptorName(workspaceRoot) ?? text(tableOf3(config, "project").name) ?? path13.basename(workspaceRoot);
3358
3423
  const deploy = tableOf3(config, "deploy");
3359
3424
  const platform = tableOf3(deploy, "platform");
3360
3425
  const azure = tableOf3(config, "azure");
@@ -3400,22 +3465,22 @@ function discoverRecordedDeployments(root) {
3400
3465
  return found;
3401
3466
  }
3402
3467
  function unavailableProvidersForProject(root) {
3403
- const workspaceRoot = findWorkspaceRoot4(root) ?? path12.resolve(root);
3468
+ const workspaceRoot = findWorkspaceRoot4(root) ?? path13.resolve(root);
3404
3469
  const agentRoot2 = findSubProjectRoot6("agent", workspaceRoot);
3405
3470
  if (agentRoot2 === null) return {};
3406
3471
  let runtime = "agentcore";
3407
3472
  let azureProtocolUnsupported = false;
3408
3473
  try {
3409
- const cfg = loadStudioToml6(path12.join(agentRoot2, "studio.toml"));
3474
+ const cfg = loadStudioToml6(path13.join(agentRoot2, "studio.toml"));
3410
3475
  runtime = text(tableOf3(cfg, "stack").runtime) ?? "agentcore";
3411
3476
  const faces = stackFaces(tableOf3(cfg, "stack"), tableOf3(cfg, "payments"));
3412
- azureProtocolUnsupported = !hasA2aFace(faces) || hasMcpFace(faces);
3477
+ azureProtocolUnsupported = hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces);
3413
3478
  } catch {
3414
3479
  return {};
3415
3480
  }
3416
3481
  if (runtime === "azure-foundry") {
3417
3482
  const reason = "this project uses a different container adapter; scaffold an agentcore project before selecting this provider";
3418
- const azureProtocolReason = "Azure Foundry deploy currently supports A2A projects only; use an A2A azure-foundry scaffold or AgentCore for MCP";
3483
+ const azureProtocolReason = "Azure Foundry deploy supports A2A and X402 seller projects; use AgentCore for MCP";
3419
3484
  return {
3420
3485
  aws: reason,
3421
3486
  ...azureProtocolUnsupported ? {
@@ -3501,38 +3566,6 @@ async function selectDeployProvider(opts) {
3501
3566
  return promptProvider(opts);
3502
3567
  }
3503
3568
 
3504
- // src/cli/_packageMetadata.ts
3505
- import * as fs14 from "fs";
3506
- import * as path13 from "path";
3507
- import { fileURLToPath as fileURLToPath2 } from "url";
3508
- function packageRoot() {
3509
- let dir = path13.dirname(fileURLToPath2(import.meta.url));
3510
- for (; ; ) {
3511
- const packageJson = path13.join(dir, "package.json");
3512
- if (fs14.existsSync(packageJson)) return dir;
3513
- const parent = path13.dirname(dir);
3514
- if (parent === dir) {
3515
- throw new Error("cannot locate the studio-cli package root");
3516
- }
3517
- dir = parent;
3518
- }
3519
- }
3520
- function pnpmVersion() {
3521
- if ("10.24.0") {
3522
- return "10.24.0";
3523
- }
3524
- const file = path13.join(packageRoot(), "package.json");
3525
- const pkg = JSON.parse(fs14.readFileSync(file, "utf-8"));
3526
- const value = String(pkg.packageManager ?? "");
3527
- const match = /^pnpm@(.+)$/u.exec(value);
3528
- if (!match?.[1]) {
3529
- throw new Error(
3530
- `studio-cli packageManager must pin pnpm (expected "pnpm@<version>" in ${file})`
3531
- );
3532
- }
3533
- return match[1];
3534
- }
3535
-
3536
3569
  // src/cli/_runtime/azureFoundry.ts
3537
3570
  import * as crypto2 from "crypto";
3538
3571
  import * as fs18 from "fs";
@@ -4474,22 +4507,23 @@ var checkEntrypointAndDockerfile = async (root, _target) => {
4474
4507
  const findings = [];
4475
4508
  const cfg = loadStudioCfg(deployWorkspaceRoot(root));
4476
4509
  const faces = stackFaces(tableOf4(cfg, "stack"), tableOf4(cfg, "payments"));
4477
- if (!hasA2aFace(faces) || hasMcpFace(faces)) {
4510
+ if (hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces)) {
4478
4511
  return [
4479
4512
  {
4480
4513
  level: "CRITICAL",
4481
4514
  name: "azure_protocol_supported",
4482
- message: "azure-foundry deploy currently supports protocol A2A only. The delegated Foundry version declares the invocations contract (:8088, /readiness, /invocations), not native MCP /mcp. Re-scaffold with --protocols A2A (optionally X402) or use AgentCore for MCP.",
4515
+ message: "azure-foundry deploy supports the A2A carrier, including X402-only seller configs. The delegated Foundry version declares the invocations contract (:8088, /readiness, /invocations), not native MCP /mcp. Re-scaffold with --protocols A2A, X402, or A2A,X402; or use AgentCore for MCP.",
4483
4516
  details: { faces }
4484
4517
  }
4485
4518
  ];
4486
4519
  }
4487
- const entry = "src/foundryMain.ts";
4520
+ const entryCandidates = ["src/unifiedMain.ts", "src/foundryMain.ts"];
4521
+ const entry = entryCandidates.find((c2) => isFile6(path17.join(agentRoot2, c2))) ?? entryCandidates[0];
4488
4522
  if (!isFile6(path17.join(agentRoot2, entry))) {
4489
4523
  findings.push({
4490
4524
  level: "CRITICAL",
4491
4525
  name: "azure_agent_entrypoint",
4492
- message: `app/agent/${entry} is missing \u2014 the A2A Foundry entrypoint the container image runs. Re-scaffold with \`bag init \u2026 --runtime azure-foundry\`.`,
4526
+ message: `app/agent/${entry} is missing \u2014 the A2A entrypoint the container image runs. Re-scaffold with \`bag init \u2026 --runtime azure-foundry\`.`,
4493
4527
  details: { entrypoint: entry }
4494
4528
  });
4495
4529
  }
@@ -4592,7 +4626,11 @@ import * as walletRt2 from "@bnbagent/studio-runtime/wallet";
4592
4626
  import { generateText } from "ai";
4593
4627
 
4594
4628
  // src/cli/_pieverseHelpers.ts
4595
- import { fromRaw as fromRaw2, getNetwork as getNetwork3 } from "@bnbagent/studio-runtime/networks";
4629
+ import {
4630
+ BSC_TESTNET_U_FAUCET_URL,
4631
+ fromRaw as fromRaw2,
4632
+ getNetwork as getNetwork3
4633
+ } from "@bnbagent/studio-runtime/networks";
4596
4634
  import {
4597
4635
  siweLogin
4598
4636
  } from "@bnbagent/studio-runtime/pieverse";
@@ -4645,9 +4683,7 @@ function printUBalanceShortfall(walletAddress, currentRaw, neededRaw, neededUsd,
4645
4683
  ` swap on PancakeSwap: https://pancakeswap.finance/swap?outputCurrency=${u.address}`
4646
4684
  );
4647
4685
  } else {
4648
- printErr(
4649
- " testnet U faucet URL is TBD \u2014 see docs/guides/pieverse-integration.md \xA76"
4650
- );
4686
+ printErr(` testnet U faucet: ${BSC_TESTNET_U_FAUCET_URL}`);
4651
4687
  }
4652
4688
  }
4653
4689
  function writeEnvLocal(key, value, envPath = ".env.local") {
@@ -6436,6 +6472,7 @@ import {
6436
6472
  findProjectRoot as findProjectRoot3,
6437
6473
  loadStudioToml as loadStudioToml10
6438
6474
  } from "@bnbagent/studio-runtime/config";
6475
+ import { tbnbFaucetHint as tbnbFaucetHint2 } from "@bnbagent/studio-runtime/networks";
6439
6476
  import { buildPolicy, buildWallet } from "@bnbagent/studio-runtime/wallet";
6440
6477
 
6441
6478
  // src/cli/walletSession.ts
@@ -6453,8 +6490,8 @@ import {
6453
6490
  import { auditedOp as auditedOp2 } from "@bnbagent/studio-runtime/audit";
6454
6491
  import { loadStudioToml as loadStudioToml9 } from "@bnbagent/studio-runtime/config";
6455
6492
  import {
6456
- BSC_TESTNET_FAUCET_URLS,
6457
6493
  getNetwork as getNetwork5,
6494
+ tbnbFaucetHint,
6458
6495
  toRaw as toRaw2
6459
6496
  } from "@bnbagent/studio-runtime/networks";
6460
6497
  import { writePrivate } from "@bnbagent/studio-runtime/secretWrite";
@@ -6524,7 +6561,7 @@ async function requireAltanaAdminGas(ctx) {
6524
6561
  }
6525
6562
  if (balance !== 0n) return;
6526
6563
  const symbol = ctx.networkName === "bsc-testnet" ? "tBNB" : "BNB";
6527
- const funding = ctx.networkName === "bsc-testnet" ? ` Fund it and retry. Testnet faucets: ${BSC_TESTNET_FAUCET_URLS.join(", ")}` : " Fund it with BNB and retry.";
6564
+ const funding = ctx.networkName === "bsc-testnet" ? ` Fund it and retry \u2014 ${tbnbFaucetHint(ctx.address)}` : " Fund it with BNB and retry.";
6528
6565
  throw new Error(
6529
6566
  `Altana admin wallet ${ctx.address} has 0 ${symbol} on ${ctx.networkName} and cannot pay gas for session administration.${funding}`
6530
6567
  );
@@ -6986,6 +7023,14 @@ function projectNetwork(projectRoot) {
6986
7023
  const dflt = net2 !== null && typeof net2 === "object" ? net2.default : void 0;
6987
7024
  return dflt ? String(dflt) : "bsc-testnet";
6988
7025
  }
7026
+ function printNextAfterNew(projectRoot, address) {
7027
+ const network = projectNetwork(projectRoot);
7028
+ const fund = network === "bsc-testnet" ? `fund it (free, only needed for paid models / on-chain settle): ${tbnbFaucetHint2(address)}` : "fund it with BNB (gas) + U before selling paid work";
7029
+ printErr(
7030
+ `Next: ${fund}
7031
+ then \`bag doctor\` to verify the project, \`bag dev\` to run it locally.`
7032
+ );
7033
+ }
6989
7034
  function twakProvider(projectRoot, walletCfg) {
6990
7035
  return buildWallet(walletCfg, projectRoot, {
6991
7036
  network: projectNetwork(projectRoot)
@@ -7179,6 +7224,8 @@ async function cmdNew(opts) {
7179
7224
  printErr(
7180
7225
  "Altana admin keystore created. Fund this address with about 0.05 tBNB for testnet bootstrap/registration, then run `bag wallet session grant` to create the bounded runtime session."
7181
7226
  );
7227
+ } else {
7228
+ printNextAfterNew(projectRoot, provider.address);
7182
7229
  }
7183
7230
  return 0;
7184
7231
  }
@@ -7218,6 +7265,7 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
7218
7265
  const address = provider.address;
7219
7266
  printOut(address);
7220
7267
  persistAddress(projectRoot, address);
7268
+ printNextAfterNew(projectRoot, address);
7221
7269
  return 0;
7222
7270
  }
7223
7271
  function ensureTwakCredentials(walletFile, homeDir) {
@@ -7950,6 +7998,44 @@ function enclosingProjectRoot(start) {
7950
7998
  }
7951
7999
  }
7952
8000
  async function cmdInit(nameArg, opts) {
8001
+ const target = path23.resolve(process.cwd(), nameArg);
8002
+ const targetPreexisted = fs24.existsSync(target);
8003
+ const cleanupOnCancel = () => {
8004
+ if (targetPreexisted || !fs24.existsSync(target)) {
8005
+ printErr("cancelled: no project was created.");
8006
+ return;
8007
+ }
8008
+ const walletsDir = path23.join(target, ".studio", "wallets");
8009
+ const hasWallet = fs24.existsSync(walletsDir) && fs24.readdirSync(walletsDir).length > 0;
8010
+ if (hasWallet) {
8011
+ printErr(
8012
+ `cancelled: ${target} is KEPT \u2014 it already contains a wallet keystore (.studio/wallets/). Finish setup there, or back the keystore up before removing the directory.`
8013
+ );
8014
+ } else {
8015
+ fs24.rmSync(target, { recursive: true, force: true });
8016
+ printErr(
8017
+ `cancelled: removed the partially created ${target}; re-run \`bag init\` to start over.`
8018
+ );
8019
+ }
8020
+ };
8021
+ const onSigint = () => {
8022
+ cleanupOnCancel();
8023
+ process.exit(130);
8024
+ };
8025
+ process.once("SIGINT", onSigint);
8026
+ try {
8027
+ return await cmdInitFlow(nameArg, opts);
8028
+ } catch (exc) {
8029
+ if (exc instanceof Error && exc.name === "PromptCancelled") {
8030
+ cleanupOnCancel();
8031
+ return 130;
8032
+ }
8033
+ throw exc;
8034
+ } finally {
8035
+ process.removeListener("SIGINT", onSigint);
8036
+ }
8037
+ }
8038
+ async function cmdInitFlow(nameArg, opts) {
7953
8039
  const target = path23.resolve(process.cwd(), nameArg);
7954
8040
  let projectName2 = path23.basename(target);
7955
8041
  if (!projectName2) {
@@ -7958,6 +8044,14 @@ async function cmdInit(nameArg, opts) {
7958
8044
  );
7959
8045
  return 2;
7960
8046
  }
8047
+ if (opts.runtime === "agentcore" || opts.destination === "platform") {
8048
+ try {
8049
+ projectName2 = validateProjectName(projectName2);
8050
+ } catch (exc) {
8051
+ printErr(`error: ${exc instanceof Error ? exc.message : exc}`);
8052
+ return 2;
8053
+ }
8054
+ }
7961
8055
  if (opts.protocols !== void 0 && opts.protocol !== void 0) {
7962
8056
  printErr("error: pass either --protocols or --protocol, not both.");
7963
8057
  return 2;
@@ -8048,7 +8142,9 @@ async function cmdInit(nameArg, opts) {
8048
8142
  return 2;
8049
8143
  }
8050
8144
  if (fs24.existsSync(target) && !opts.force) {
8051
- printErr(`error: ${target} already exists. Use --force to overwrite.`);
8145
+ printErr(
8146
+ `error: ${target} already exists (perhaps from an interrupted \`bag init\`). Re-run with --force to overwrite \u2014 this DELETES the whole directory, including any wallet keystore under its .studio/ \u2014 or pick another name.`
8147
+ );
8052
8148
  return 2;
8053
8149
  }
8054
8150
  if (opts.destination === "platform" && opts.network === "bsc-mainnet") {
@@ -8072,13 +8168,20 @@ async function cmdInit(nameArg, opts) {
8072
8168
  destination = "self";
8073
8169
  runtime = "agentcore";
8074
8170
  }
8075
- if (destination === "self" && runtime === "azure-foundry" && (!hasA2aFace(faces) || hasMcpFace(faces))) {
8171
+ if (destination === "self" && runtime === "azure-foundry" && (hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces))) {
8076
8172
  printErr(
8077
- "error: azure-foundry supports protocol A2A only as its native face (X402 is optional) and does not support an MCP face. Foundry is delegated through its invocations container contract (:8088, /readiness, /invocations), not the native MCP /mcp transport. Use --protocols A2A (optionally with X402), or use --runtime agentcore for MCP."
8173
+ "error: azure-foundry supports the A2A carrier (including X402-only seller configs) and does not support an MCP face. Foundry is delegated through its invocations container contract (:8088, /readiness, /invocations), not the native MCP /mcp transport. Use --protocols A2A, X402, or A2A,X402; or use --runtime agentcore for MCP."
8078
8174
  );
8079
8175
  return 2;
8080
8176
  }
8081
8177
  if (fs24.existsSync(target)) {
8178
+ const walletsDir = path23.join(target, ".studio", "wallets");
8179
+ if (fs24.existsSync(walletsDir) && fs24.readdirSync(walletsDir).length > 0) {
8180
+ printErr(
8181
+ `error: refusing --force: ${walletsDir} contains a wallet keystore and overwriting would DELETE the key. Back the keystore up and remove the directory yourself, or init under a different name.`
8182
+ );
8183
+ return 2;
8184
+ }
8082
8185
  fs24.rmSync(target, { recursive: true, force: true });
8083
8186
  }
8084
8187
  if (destination === "platform") {
@@ -8396,17 +8499,18 @@ function scaffold(target, name, o) {
8396
8499
  const isContainer = packaging === "container";
8397
8500
  const mode = recipeModeOf(o.faces);
8398
8501
  const stem2 = entryStemOf(o.faces);
8399
- const a2aEntry = o.runtime === "azure-foundry" ? "dist/foundryMain.js" : "dist/main.js";
8400
8502
  const runtimeCtx = {
8401
8503
  PKG: AGENT_SRC,
8402
8504
  TWAK_CLI_VERSION,
8403
8505
  PNPM_VERSION: packageManagerVersion,
8404
8506
  DEPLOYMENT_TYPE: isContainer ? "container" : "direct_code_deploy",
8405
- ENTRYPOINT: o.runtime === "azure-foundry" ? a2aEntry : `dist/${stem2}.js`,
8406
- // Foundry Hosted Agents have a provider-level container contract that is
8407
- // independent of Studio's local A2A/MCP ports: plain HTTP on :8088 plus
8408
- // GET /readiness and the declared protocol route. The deploy host below
8409
- // declares invocations, so its image must always expose :8088.
8507
+ // The A2A entrypoint (unifiedMain) is cloud-portable: it binds BOTH the
8508
+ // AgentCore (9000) and Foundry (8088) contract ports itself, so the same
8509
+ // rendered image deploys to either cloud no runtime-specific entry.
8510
+ ENTRYPOINT: `dist/${stem2}.js`,
8511
+ // AGENT_PORT only prepends a primary override; the Foundry contract port
8512
+ // stays reachable regardless. MCP keeps its 8000 contract; Foundry
8513
+ // renders 8088 for continuity with the provider's documented default.
8410
8514
  CONTAINER_PORT: o.runtime === "azure-foundry" ? "8088" : String(devPortOf(o.faces))
8411
8515
  };
8412
8516
  emitRecipe(agentRoot2, "agent", { context: runtimeCtx });
@@ -8772,10 +8876,11 @@ function renderAgentStudioToml(name, o) {
8772
8876
  # Read by the Agent: it quotes the FIXED \`price\`, CLAMPS it to [min,max],
8773
8877
  # freezes a short-TTL offer, and EIP-191 signs it \u2014 pricing is rule-based, the
8774
8878
  # LLM never prices. price=0 is FREE and is supported by the canonical stack.
8775
- currency = "${currencyAddr}" # $U token address \u2014 prefilled from [network].default
8776
- price = "${o.erc8183Price}" # token base units; 0 = FREE (zero token escrow)
8879
+ currency = "${currencyAddr}" # $U token address \u2014 prefilled from [network].default; rarely changed
8880
+ # All prices are in wei of the currency token. U has 18 decimals (not 6 like USDC).
8881
+ price = "${o.erc8183Price}" # wei; 0 = FREE (zero token escrow)
8777
8882
  min_price = "0" # wei \u2014 clamp floor
8778
- max_price = "" # wei \u2014 clamp ceiling; SET before going live
8883
+ max_price = "" # wei \u2014 clamp ceiling; empty = unbounded; SET before going live
8779
8884
  quote_ttl_seconds = 900 # seconds a signed quote stays valid; SDK caps at 900 (~15min work window)
8780
8885
  default_estimated_completion_seconds = 600
8781
8886
  poll_interval_seconds = 30
@@ -8913,7 +9018,7 @@ function renderAgentReadme(name, faces, destination, walletKind2) {
8913
9018
  const port = String(devPortOf(faces));
8914
9019
  const x402Only = faces.length === 1 && hasX402Face(faces);
8915
9020
  const surface = mode === "both" ? "A2A natively on `0.0.0.0:9000` (agent card + JSON-RPC `message/send`) and buffered streamable-HTTP MCP on `/mcp` through the platform envelope tunnel" : mode === "mcp" ? "streamable-HTTP MCP on `0.0.0.0:8000/mcp` (negotiate + notify_funded sync-delivery + read-only chain tools)" : x402Only ? "only the public `/x402` seller face; AgentCore uses an internal A2A-native process on port 9000 but the gateway suppresses A2A discovery" : "`serveA2a`: the agent card at `/.well-known/agent-card.json` + JSON-RPC `message/send` on `0.0.0.0:9000`";
8916
- const filesA2a = `- \`src/main.ts\` \u2014 A2A serving entrypoint (\`serveA2a\` on port 9000).
9021
+ const filesA2a = `- \`src/unifiedMain.ts\` \u2014 unified serving entrypoint (A2A on port 9000 + Foundry invocations on 8088).
8917
9022
  - \`src/executor.ts\` \u2014 the SellerAgentExecutor: the negotiate + notify_funded A2A skills.
8918
9023
  - \`src/agentCard.ts\` \u2014 the discoverable AgentCard (+ OAuth2/Cognito scheme).`;
8919
9024
  const filesMcp = `- \`src/mcpMain.ts\` \u2014 MCP serving entrypoint (streamable HTTP on \`/mcp\`; deploy
@@ -9063,10 +9168,23 @@ async function resolveWalletKind(flagValue, isTty) {
9063
9168
  );
9064
9169
  return "evm-local";
9065
9170
  }
9066
- const answer = (await promptUser(
9067
- "Wallet backend? [evm-local] local keystore / altana bounded session / twak Trust Wallet CLI: "
9068
- )).trim().toLowerCase();
9069
- return answer === "twak" || answer === "altana" ? answer : "evm-local";
9171
+ printOut("Wallet backend (who holds the Agent's signer key):");
9172
+ printOut(
9173
+ " 1. evm-local [default] \u2014 encrypted local keystore under .studio/; simplest, works everywhere"
9174
+ );
9175
+ printOut(
9176
+ " 2. twak \u2014 Trust Wallet CLI wallet; forces container packaging for deploys"
9177
+ );
9178
+ printOut(
9179
+ " 3. altana \u2014 bounded session signer; incompatible with pieverse-llm and paid b402 selling"
9180
+ );
9181
+ const answer = (await promptUser("Wallet backend [1-3, Enter = evm-local]: ")).trim().toLowerCase();
9182
+ if (answer === "2" || answer === "twak") return "twak";
9183
+ if (answer === "3" || answer === "altana") return "altana";
9184
+ if (answer !== "" && answer !== "1" && answer !== "evm-local") {
9185
+ printErr(`hint: unknown wallet backend '${answer}' \u2014 using evm-local.`);
9186
+ }
9187
+ return "evm-local";
9070
9188
  }
9071
9189
  async function resolveLlmProviderForWallet(walletKind2, configuredProvider, valueSource, isTty) {
9072
9190
  if (walletKind2 !== "altana") {
@@ -9249,12 +9367,22 @@ function readWalletAddress(studioToml) {
9249
9367
  async function printFaucetHint(network, address) {
9250
9368
  printOut("");
9251
9369
  if (network === "bsc-testnet") {
9252
- const { BSC_TESTNET_FAUCET_URLS: BSC_TESTNET_FAUCET_URLS5 } = await import("@bnbagent/studio-runtime/networks");
9370
+ const {
9371
+ BSC_TESTNET_TBNB_TELEGRAM_FAUCET: BSC_TESTNET_TBNB_TELEGRAM_FAUCET2,
9372
+ BSC_TESTNET_FAUCET_DOCS_URL: BSC_TESTNET_FAUCET_DOCS_URL2,
9373
+ BSC_TESTNET_U_FAUCET_URL: BSC_TESTNET_U_FAUCET_URL4
9374
+ } = await import("@bnbagent/studio-runtime/networks");
9253
9375
  printOut(`Your testnet wallet address: ${address}`);
9254
- printOut("Fund it (free) from these faucets \u2014 paste the address above:");
9255
- for (const url of BSC_TESTNET_FAUCET_URLS5) {
9256
- printOut(` \xB7 ${url}`);
9257
- }
9376
+ printOut("Fund it (free):");
9377
+ printOut(
9378
+ ` tBNB \u2014 message the official Telegram bot ${BSC_TESTNET_TBNB_TELEGRAM_FAUCET2}`
9379
+ );
9380
+ printOut(
9381
+ ` send: "I would like to get tBNB to my wallet ${address}"`
9382
+ );
9383
+ printOut(" (up to 0.3 tBNB per day; it replies with the tx hash)");
9384
+ printOut(` more ways to get tBNB: ${BSC_TESTNET_FAUCET_DOCS_URL2}`);
9385
+ printOut(` $U \u2014 ${BSC_TESTNET_U_FAUCET_URL4}`);
9258
9386
  printOut("(Faucets are needed only for paid models / on-chain settle.");
9259
9387
  printOut(" The default `auto/free` LLM model and AgentCore deploy");
9260
9388
  printOut(" do NOT require any funds.)");
@@ -9618,18 +9746,26 @@ function printMainTwakWalletWarning() {
9618
9746
  );
9619
9747
  }
9620
9748
  async function onboardIpfsKey(envPath, ipfsKey) {
9749
+ const url = (await promptUser(
9750
+ "\nIPFS pinning-service UPLOAD ENDPOINT for deliverable storage \u2014 REQUIRED before `bag deploy` (e.g. your provider's pin/upload URL or a self-hosted node's /api/v0/add; blank to fill STORAGE_API_URL later): "
9751
+ )).trim();
9752
+ if (url) {
9753
+ setEnvVar(envPath, "STORAGE_API_URL", url);
9754
+ printOut("\u2713 STORAGE_API_URL written to .studio/.env.local");
9755
+ }
9621
9756
  let key = ipfsKey;
9622
9757
  if (key === void 0) {
9623
9758
  key = (await promptUser(
9624
- "\nIPFS pinning-service write key/JWT for deliverable storage (blank to skip, fill STORAGE_API_KEY later): "
9759
+ "IPFS pinning-service write key/JWT (blank to skip, fill STORAGE_API_KEY later): "
9625
9760
  )).trim();
9626
9761
  }
9627
9762
  if (key) {
9628
9763
  setEnvVar(envPath, "STORAGE_API_KEY", key);
9629
9764
  printOut("\u2713 STORAGE_API_KEY written to .studio/.env.local");
9630
- } else {
9765
+ }
9766
+ if (!url || !key) {
9631
9767
  printErr(
9632
- "hint: set STORAGE_API_URL (your pinning service's upload endpoint) and STORAGE_API_KEY (its write key/JWT)\n in .studio/.env.local before `bag dev`, or re-scaffold with --storage-provider local for offline dev."
9768
+ "hint: set STORAGE_API_URL (your pinning service's upload endpoint) and STORAGE_API_KEY (its write key/JWT)\n in .studio/.env.local before `bag dev`, or re-scaffold with --storage-provider local for offline dev.\n `bag deploy prepare` blocks (CRITICAL) until STORAGE_API_URL is set."
9633
9769
  );
9634
9770
  }
9635
9771
  }
@@ -9651,7 +9787,7 @@ function printCampaignIntro() {
9651
9787
  );
9652
9788
  }
9653
9789
  function printTwakNotice(destination = "self") {
9654
- const deployLine = destination === "platform" ? " \xB7 DEPLOY (managed platform): builds + pushes the arm64 twak image\n (Node + the twak CLI) FROM YOUR MACHINE \u2014 local Docker is\n REQUIRED (no CodeBuild fallback on this path); start Docker Desktop." : " \xB7 RUN/DEPLOY: local `bag dev` runs the agent IN-PROCESS by default\n (`tsx src/main.ts`, no Docker); `bag dev --container` runs it via\n `agentcore dev` in Docker for image parity. DEPLOY builds the twak\n container image (Node + the twak CLI) via AWS CodeBuild \u2014\n Docker is optional locally. `bag init` already configured\n build=Container + a Dockerfile.";
9790
+ const deployLine = destination === "platform" ? " \xB7 DEPLOY (managed platform): builds + pushes the arm64 twak image\n (Node + the twak CLI) FROM YOUR MACHINE \u2014 local Docker is\n REQUIRED (no CodeBuild fallback on this path); start Docker Desktop." : " \xB7 RUN/DEPLOY: local `bag dev` runs the agent IN-PROCESS by default\n (`tsx src/unifiedMain.ts`, no Docker); `bag dev --container` runs it via\n `agentcore dev` in Docker for image parity. DEPLOY builds the twak\n container image (Node + the twak CLI) via AWS CodeBuild \u2014\n Docker is optional locally. `bag init` already configured\n build=Container + a Dockerfile.";
9655
9791
  printOut(
9656
9792
  `
9657
9793
  NOTE \u2014 wallet.kind = "twak" (Trust Wallet Agent Kit, CLI >= ${TWAK_CLI_VERSION}):
@@ -9758,9 +9894,9 @@ function entrypointHint(faces) {
9758
9894
  return "app/agent/src/mcpMain.ts = MCP entrypoint (build your value here)";
9759
9895
  }
9760
9896
  if (faces.length === 1 && hasX402Face(faces)) {
9761
- return "app/agent/src/main.ts = X402-only runtime entrypoint (build your value here)";
9897
+ return "app/agent/src/unifiedMain.ts = X402-only runtime entrypoint (build your value here)";
9762
9898
  }
9763
- return "app/agent/src/main.ts + executor.ts = A2A entrypoint (build your value here)";
9899
+ return "app/agent/src/unifiedMain.ts + executor.ts = A2A entrypoint (build your value here)";
9764
9900
  }
9765
9901
  function hasVendoredTarballs(agentDir) {
9766
9902
  const vendor = path23.join(agentDir, "vendor");
@@ -9808,18 +9944,17 @@ function printCompactNextSteps(name, o = {}) {
9808
9944
  " pnpm install # one-time: install the agent dependencies"
9809
9945
  );
9810
9946
  }
9947
+ printOut(" bag doctor # verify config + env before funding");
9948
+ printOut(" bag dev # run the Agent locally");
9811
9949
  if (destination === "platform") {
9812
- printOut(" bag dev # run the Agent locally");
9813
9950
  printOut(
9814
9951
  " bag deploy --provider bnb # Agent \u2192 managed platform (48h testnet trial)"
9815
9952
  );
9816
9953
  } else if (runtime === "azure-foundry") {
9817
- printOut(" bag dev # run the Agent locally");
9818
9954
  printOut(
9819
9955
  " bag deploy --provider azure # Agent \u2192 Azure AI Foundry (delegated to bnbagent-deploy; browser login, no azd)"
9820
9956
  );
9821
9957
  } else {
9822
- printOut(" agentcore dev # run the Agent locally on AgentCore");
9823
9958
  printOut(" bag deploy --provider aws # Agent \u2192 AgentCore");
9824
9959
  }
9825
9960
  printOut("");
@@ -9949,19 +10084,7 @@ function printNextSteps(name, provider, o = {}) {
9949
10084
  printOut(" # is `auto/free` (Free) \u2014 no funding required to start.");
9950
10085
  printOut(" bag llm activate");
9951
10086
  printOut("");
9952
- printOut(
9953
- " # 4. (optional) fund the wallet \u2014 only when you need paid model / deploy / publish:"
9954
- );
9955
- printOut(
9956
- " # testnet: send testnet BNB (gas) + testnet U to the address above"
9957
- );
9958
- printOut(" # mainnet: swap a small amount via PancakeSwap:");
9959
- printOut(
9960
- " # https://pancakeswap.finance/swap?outputCurrency=0xcE24439F2D9C6a2289F741120FE202248B666666"
9961
- );
9962
- printOut(" # Then: bag llm topup --amount N (allocate paid credits)");
9963
- printOut("");
9964
- nextStep = 5;
10087
+ nextStep = 4;
9965
10088
  } else {
9966
10089
  const keyEnv = PROVIDER_KEY_ENV[provider];
9967
10090
  if (keyEnv) {
@@ -9973,6 +10096,26 @@ function printNextSteps(name, provider, o = {}) {
9973
10096
  }
9974
10097
  nextStep = 4;
9975
10098
  }
10099
+ printOut(` # ${nextStep}. verify + run the agent locally (no funds needed)`);
10100
+ printOut(" bag doctor # diagnose config + env; fix FAILs before deploy");
10101
+ printOut(" bag dev # serve the Agent locally for a smoke test");
10102
+ nextStep += 1;
10103
+ if (provider === "pieverse-llm") {
10104
+ printOut("");
10105
+ printOut(
10106
+ ` # ${nextStep}. (optional) fund the wallet \u2014 only when you need paid model / deploy / publish:`
10107
+ );
10108
+ printOut(
10109
+ " # testnet: send testnet BNB (gas) + testnet U to the address above"
10110
+ );
10111
+ printOut(" # mainnet: swap a small amount via PancakeSwap:");
10112
+ printOut(
10113
+ " # https://pancakeswap.finance/swap?outputCurrency=0xcE24439F2D9C6a2289F741120FE202248B666666"
10114
+ );
10115
+ printOut(" # Then: bag llm topup --amount N (allocate paid credits)");
10116
+ nextStep += 1;
10117
+ }
10118
+ printOut("");
9976
10119
  printOut(
9977
10120
  ` # ${nextStep}. review ERC-8183 pricing in studio.toml [payments.erc8183]`
9978
10121
  );
@@ -9980,10 +10123,6 @@ function printNextSteps(name, provider, o = {}) {
9980
10123
  " # (price was selected at init; `bag config set payments.erc8183.price 0` explicitly switches to FREE)"
9981
10124
  );
9982
10125
  nextStep += 1;
9983
- printOut(` # ${nextStep}. verify + run the agent locally`);
9984
- printOut(" bag doctor");
9985
- printOut(" bag dev");
9986
- nextStep += 1;
9987
10126
  if (destination === "platform") {
9988
10127
  printOut(
9989
10128
  ` # ${nextStep}. deploy: app/agent \u2192 managed platform (48h testnet trial)`
@@ -10284,6 +10423,11 @@ function runtimeEnvKeysCore(cfg, resolvable) {
10284
10423
  if (resolvable("RPC_URL")) {
10285
10424
  keys.push("RPC_URL");
10286
10425
  }
10426
+ const runtimeName = String(tableOf8(cfg, "stack").runtime ?? "agentcore");
10427
+ const publicUrlKeys = runtimeName === "azure-foundry" ? ["BNBAGENT_PUBLIC_URL"] : ["BNBAGENT_PUBLIC_URL", "AGENT_PUBLIC_URL"];
10428
+ for (const key of publicUrlKeys) {
10429
+ if (resolvable(key)) keys.push(key);
10430
+ }
10287
10431
  for (const key of PAYMASTER_URL_ENV_KEYS) {
10288
10432
  if (resolvable(key)) keys.push(key);
10289
10433
  }
@@ -10292,8 +10436,7 @@ function runtimeEnvKeysCore(cfg, resolvable) {
10292
10436
  if (resolvable(key)) keys.push(key);
10293
10437
  }
10294
10438
  }
10295
- const runtime = String(tableOf8(cfg, "stack").runtime ?? "agentcore");
10296
- if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
10439
+ if (X402_CAPABLE_RUNTIMES.has(runtimeName) && x402SellerUsesB402(cfg)) {
10297
10440
  for (const key of B402_RUNTIME_KEYS) {
10298
10441
  if (resolvable(key)) keys.push(key);
10299
10442
  }
@@ -10399,8 +10542,12 @@ function agentFaces(workspaceRoot) {
10399
10542
  const cfg = loadAgentToml2(workspaceRoot);
10400
10543
  return stackFaces(tableOf9(cfg, "stack"), tableOf9(cfg, "payments"));
10401
10544
  }
10402
- function localEntryFile(faces) {
10403
- return `src/${entryStemOf(faces)}.ts`;
10545
+ function localEntryFile(faces, agentDir) {
10546
+ const stem2 = entryStemOf(faces);
10547
+ const candidates = [stem2, ...LEGACY_ENTRY_STEMS[stem2]].map(
10548
+ (s) => `src/${s}.ts`
10549
+ );
10550
+ return candidates.find((c2) => isFile10(path24.join(agentDir, c2))) ?? candidates[0];
10404
10551
  }
10405
10552
  function defaultAgentPort(faces) {
10406
10553
  return devPortOf(faces);
@@ -10772,11 +10919,11 @@ async function cmdDev(opts) {
10772
10919
  const agentPort = opts.port ?? defaultAgentPort(faces);
10773
10920
  const runtime = agentRuntime(workspaceRoot);
10774
10921
  const container = Boolean(opts.container);
10775
- const entryFile = localEntryFile(faces);
10922
+ const entryFile = localEntryFile(faces, agentDir);
10776
10923
  const agentFile = path24.join(agentDir, entryFile);
10777
10924
  if (!isFile10(agentFile)) {
10778
10925
  printErr(
10779
- `error: Agent entrypoint file ${agentFile} does not exist. [stack] faces = [${faces.join(", ")}], so the entrypoint is ${entryFile} (A2A/X402-only \u2192 src/main.ts, MCP \u2192 src/mcpMain.ts, A2A+MCP \u2192 src/dualMain.ts). Run \`bag init\` to scaffold the workspace.`
10926
+ `error: Agent entrypoint file ${agentFile} does not exist. [stack] faces = [${faces.join(", ")}], so the entrypoint is ${entryFile} (A2A/X402-only \u2192 src/unifiedMain.ts, MCP \u2192 src/mcpMain.ts, A2A+MCP \u2192 src/dualMain.ts; legacy src/main.ts scaffolds still run). Run \`bag init\` to scaffold the workspace.`
10780
10927
  );
10781
10928
  return 2;
10782
10929
  }
@@ -10915,7 +11062,7 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
10915
11062
  printOut(
10916
11063
  `bag dev: starting Agent in-process (\`tsx ${args.join(" ")}\` on :${agentPort}, no Docker \u2014 the entrypoint self-serves; cwd=${agentDir}, runner=${runner2})`
10917
11064
  );
10918
- if (runtime === RUNTIME_AZURE_FOUNDRY) {
11065
+ if (runtime === RUNTIME_AZURE_FOUNDRY && isFile10(path24.join(agentDir, "src/foundryMain.ts"))) {
10919
11066
  printOut(
10920
11067
  "bag dev: azure-foundry serves this local A2A/MCP entrypoint in-process; src/foundryMain.ts is the deploy-only Foundry host (the entrypoint `bag doctor` reports) and never runs here."
10921
11068
  );
@@ -11088,7 +11235,10 @@ async function checkAgentPackagePresent(root, target) {
11088
11235
  const cfg = loadAgentToml(root);
11089
11236
  const faces = stackFaces(tableOf2(cfg, "stack"), tableOf2(cfg, "payments"));
11090
11237
  const stem2 = entryStemOf(faces);
11091
- const sourceEntries = [`src/${stem2}.ts`];
11238
+ const effectiveStem = [stem2, ...LEGACY_ENTRY_STEMS[stem2]].find(
11239
+ (s) => isFile11(path25.join(agentRoot2, `src/${s}.ts`))
11240
+ ) ?? stem2;
11241
+ const sourceEntries = [`src/${effectiveStem}.ts`];
11092
11242
  if (stem2 === "dualMain") {
11093
11243
  sourceEntries.push("src/mcpMain.ts");
11094
11244
  }
@@ -11106,7 +11256,7 @@ async function checkAgentPackagePresent(root, target) {
11106
11256
  }
11107
11257
  ];
11108
11258
  }
11109
- const distEntries = [`dist/${stem2}.js`];
11259
+ const distEntries = [`dist/${effectiveStem}.js`];
11110
11260
  if (stem2 === "dualMain") {
11111
11261
  distEntries.push("dist/mcpMain.js");
11112
11262
  }
@@ -11586,12 +11736,12 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
11586
11736
  }
11587
11737
  const destination = String(tableOf2(cfg, "deploy").destination ?? "self");
11588
11738
  const stackRuntime2 = String(tableOf2(cfg, "stack").runtime ?? "agentcore");
11589
- if (rails.x402 && (free || credentials.complete) && destination !== "platform" && (target !== "agentcore" || stackRuntime2 !== "agentcore")) {
11590
- const blocking = target !== "agentcore" ? target : stackRuntime2;
11739
+ if (rails.x402 && (free || credentials.complete) && !target.startsWith("platform") && !(X402_CAPABLE_RUNTIMES.has(target) && X402_CAPABLE_RUNTIMES.has(stackRuntime2))) {
11740
+ const blocking = !X402_CAPABLE_RUNTIMES.has(target) ? target : stackRuntime2;
11591
11741
  out.push({
11592
11742
  level: Level.WARNING,
11593
11743
  name: "x402_forced_dormant_runtime",
11594
- message: `x402 pricing is ready, but the ${blocking} runtime has no x402 path; this target is forced dormant. Deploy to AgentCore (managed platform or self-hosted) to activate the rail.`,
11744
+ message: `x402 pricing is ready, but the ${blocking} runtime has no x402 path; this target is forced dormant. Deploy to AgentCore or Azure Foundry (managed platform or self-hosted) to activate the rail.`,
11595
11745
  details: { destination, target, stackRuntime: stackRuntime2 }
11596
11746
  });
11597
11747
  }
@@ -11642,7 +11792,7 @@ async function checkCommerceReady(root, target) {
11642
11792
  return out;
11643
11793
  }
11644
11794
  async function checkDeployCliRunnable(_root, target) {
11645
- if (target !== "agentcore") {
11795
+ if (target !== "agentcore" && target !== "platform" && target !== "platform-azure") {
11646
11796
  return [];
11647
11797
  }
11648
11798
  const override = (process.env.BNBAGENT_DEPLOY_COMMAND ?? "").trim();
@@ -13048,7 +13198,11 @@ import {
13048
13198
  findSubProjectRoot as findSubProjectRoot13,
13049
13199
  loadStudioToml as loadStudioToml17
13050
13200
  } from "@bnbagent/studio-runtime/config";
13051
- import { BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS2 } from "@bnbagent/studio-runtime/networks";
13201
+ import {
13202
+ BSC_TESTNET_FAUCET_DOCS_URL,
13203
+ BSC_TESTNET_TBNB_TELEGRAM_FAUCET,
13204
+ BSC_TESTNET_U_FAUCET_URL as BSC_TESTNET_U_FAUCET_URL2
13205
+ } from "@bnbagent/studio-runtime/networks";
13052
13206
 
13053
13207
  // src/cli/_deploy/checks/warning.ts
13054
13208
  import * as crypto4 from "crypto";
@@ -13358,7 +13512,10 @@ var checkPlatformEntrypointPresent = async (root, _target) => {
13358
13512
  const data = loadAgent(root);
13359
13513
  const faces = stackFaces(tableOf11(data, "stack"), tableOf11(data, "payments"));
13360
13514
  const stem2 = entryStemOf(faces);
13361
- const filenames = [`${stem2}.ts`];
13515
+ const effectiveStem = [stem2, ...LEGACY_ENTRY_STEMS[stem2]].find(
13516
+ (s) => fs35.existsSync(path34.join(agentRoot(root), "src", `${s}.ts`))
13517
+ ) ?? stem2;
13518
+ const filenames = [`${effectiveStem}.ts`];
13362
13519
  if (stem2 === "dualMain") filenames.push("mcpMain.ts");
13363
13520
  const filename = filenames.find(
13364
13521
  (candidate) => !fs35.existsSync(path34.join(agentRoot(root), "src", candidate))
@@ -13522,8 +13679,14 @@ var checkPlatformFundingHint = async (_root, _target) => [
13522
13679
  {
13523
13680
  level: Level.INFO,
13524
13681
  name: "platform_funding_hint",
13525
- message: `testnet trial \u2014 keep a little tBNB for gas and testnet $U for commerce. Faucets: ${BSC_TESTNET_FAUCET_URLS2.join(" \xB7 ")}`,
13526
- details: { faucets: [...BSC_TESTNET_FAUCET_URLS2] }
13682
+ message: `testnet trial \u2014 keep a little tBNB for gas and testnet $U for commerce. tBNB: message ${BSC_TESTNET_TBNB_TELEGRAM_FAUCET} (more options: ${BSC_TESTNET_FAUCET_DOCS_URL}) \xB7 $U: ${BSC_TESTNET_U_FAUCET_URL2}`,
13683
+ details: {
13684
+ faucets: [
13685
+ BSC_TESTNET_TBNB_TELEGRAM_FAUCET,
13686
+ BSC_TESTNET_FAUCET_DOCS_URL,
13687
+ BSC_TESTNET_U_FAUCET_URL2
13688
+ ]
13689
+ }
13527
13690
  }
13528
13691
  ];
13529
13692
  var criticalChecks = [
@@ -13532,6 +13695,7 @@ var criticalChecks = [
13532
13695
  checkPlatformTestnetOnly,
13533
13696
  checkPlatformSlugValid,
13534
13697
  checkPlatformLoggedIn,
13698
+ checkDeployCliRunnable,
13535
13699
  checkPlatformDockerAvailable,
13536
13700
  checkPlatformStorageEndpoint,
13537
13701
  checkTwakCustomContractsUnsupported,
@@ -14294,7 +14458,7 @@ async function platformAgent(opts) {
14294
14458
  const root = opts.root;
14295
14459
  const backend = opts.backend ?? "aws";
14296
14460
  const isTty = opts.isTty ?? stdinIsTty;
14297
- const ask = opts.promptUser ?? promptUser;
14461
+ const ask2 = opts.promptUser ?? promptUser;
14298
14462
  warn(
14299
14463
  `note: deploying to the BNB Chain managed platform (backend=${backend}) \u2014 a 48h TESTNET trial sandbox (network is forced to bsc-testnet; the runtime is auto-reclaimed at 48h). Not a production seller.`
14300
14464
  );
@@ -14303,12 +14467,6 @@ async function platformAgent(opts) {
14303
14467
  const cfg2 = loadAgentCfg(root);
14304
14468
  const faces2 = stackFaces(tableOf12(cfg2, "stack"), tableOf12(cfg2, "payments"));
14305
14469
  const protocol2 = nativeProtocolOf(faces2);
14306
- if (hasX402Face(faces2)) {
14307
- warn(
14308
- "error: x402 publication is not supported on the managed Azure backend. No build or upload was started."
14309
- );
14310
- return 1;
14311
- }
14312
14470
  const runtimeProfile = protocol2 === "A2A" ? "foundry-responses-v1" : "foundry-invocations-v1";
14313
14471
  const capability = await platformCmd(["capabilities"], { json: true });
14314
14472
  const platform = isJsonObject(capability.data.platform) ? capability.data.platform : {};
@@ -14322,6 +14480,12 @@ async function platformAgent(opts) {
14322
14480
  );
14323
14481
  return capability.code || 1;
14324
14482
  }
14483
+ if (hasX402Face(faces2) && azure.x402 !== true) {
14484
+ warn(
14485
+ "error: this platform deployment does not accept x402 publication on the managed Azure backend yet. No build or upload was started. Deploy without the X402 face, or self-host the x402 gateway (`bag deploy --provider azure` + docs/guides/self-hosted-x402-gateway-azure.md)."
14486
+ );
14487
+ return 1;
14488
+ }
14325
14489
  }
14326
14490
  const campaignProbe = opts.campaignActive ?? (async () => null);
14327
14491
  const trialRes = await platformCmd(["trial"], { json: true });
@@ -14350,7 +14514,7 @@ async function platformAgent(opts) {
14350
14514
  const rc = await termsConsentGate(root, {
14351
14515
  acceptRisk: opts.acceptRisk ?? false,
14352
14516
  isTty,
14353
- promptUser: ask
14517
+ promptUser: ask2
14354
14518
  });
14355
14519
  if (rc !== null) {
14356
14520
  return rc;
@@ -14361,7 +14525,7 @@ async function platformAgent(opts) {
14361
14525
  const confirm = opts.confirmPackaging ?? ((r, p) => confirmPackagingDefault(r, p, {
14362
14526
  acceptRisk: opts.acceptRisk ?? false,
14363
14527
  isTty,
14364
- promptUser: ask
14528
+ promptUser: ask2
14365
14529
  }));
14366
14530
  const rc = await confirm(root, packaging);
14367
14531
  if (rc !== null && rc !== 0) {
@@ -16847,12 +17011,13 @@ import { pieverseKeyHash as pieverseKeyHash4 } from "@bnbagent/studio-runtime/ll
16847
17011
  import {
16848
17012
  BSC_MAINNET_MIN_BNB,
16849
17013
  BSC_MAINNET_MIN_U,
16850
- BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS3,
16851
17014
  BSC_TESTNET_MIN_BNB,
16852
17015
  BSC_TESTNET_MIN_U,
17016
+ BSC_TESTNET_U_FAUCET_URL as BSC_TESTNET_U_FAUCET_URL3,
16853
17017
  ERC8183_SUBMIT_GAS_RESERVE_BNB,
16854
17018
  fromRaw as fromRaw3,
16855
- getNetwork as getNetwork9
17019
+ getNetwork as getNetwork9,
17020
+ tbnbFaucetHint as tbnbFaucetHint3
16856
17021
  } from "@bnbagent/studio-runtime/networks";
16857
17022
  import { listModels as listModels2 } from "@bnbagent/studio-runtime/pieverse";
16858
17023
  import * as walletRt5 from "@bnbagent/studio-runtime/wallet";
@@ -16957,6 +17122,9 @@ async function cmdDoctor(opts) {
16957
17122
  checks.push(...await check8004(projectRoot, data, opts.network));
16958
17123
  const destination = String(tableOf14(data, "deploy").destination ?? "self").trim().toLowerCase();
16959
17124
  checks.push(...await checkDeployTools(data, destination));
17125
+ checks.push(
17126
+ ...await checkPlatformZipBundle(data, destination, projectRoot)
17127
+ );
16960
17128
  checks.push(...checkAgentsMdSkillTrigger(projectRoot));
16961
17129
  printChecks(checks);
16962
17130
  return checks.some((c2) => c2.status === FAIL) ? 1 : 0;
@@ -17039,16 +17207,12 @@ function checkAppMain(projectRootArg2) {
17039
17207
  }
17040
17208
  }
17041
17209
  const stack = tableOf14(config, "stack");
17210
+ const faces = stackFaces(stack, tableOf14(config, "payments"));
17211
+ const stem2 = entryStemOf(faces);
17042
17212
  const runtime = String(stack.runtime ?? "").toLowerCase();
17043
- let entrypoint;
17044
- if (runtime === "azure-foundry") {
17045
- entrypoint = "src/foundryMain.ts";
17046
- } else if (runtime === "agentcore") {
17047
- const faces = stackFaces(stack, tableOf14(config, "payments"));
17048
- entrypoint = `src/${entryStemOf(faces)}.ts`;
17049
- } else {
17050
- entrypoint = "src/main.ts";
17051
- }
17213
+ const legacyStems = runtime === "azure-foundry" && stem2 === "unifiedMain" ? ["foundryMain", "main"] : LEGACY_ENTRY_STEMS[stem2];
17214
+ const candidates = [stem2, ...legacyStems].map((s) => `src/${s}.ts`);
17215
+ const entrypoint = candidates.find((c2) => isFile17(path39.join(agentDir, c2))) ?? candidates[0];
17052
17216
  const entryFile = path39.join(agentDir, entrypoint);
17053
17217
  if (!isFile17(entryFile)) {
17054
17218
  return [
@@ -17059,7 +17223,7 @@ function checkAppMain(projectRootArg2) {
17059
17223
  }
17060
17224
  ];
17061
17225
  }
17062
- const detail = runtime === "azure-foundry" ? `${entrypoint} (deploy entrypoint; \`bag dev\` serves src/main.ts or src/mcpMain.ts locally)` : entrypoint;
17226
+ const detail = entrypoint === "src/foundryMain.ts" ? `${entrypoint} (deploy entrypoint; \`bag dev\` serves src/main.ts or src/mcpMain.ts locally)` : entrypoint;
17063
17227
  return [{ name: "agent entrypoint", status: PASS, detail }];
17064
17228
  }
17065
17229
  function checkAgentcoreName(projectRoot) {
@@ -17837,7 +18001,8 @@ async function checkBalances(projectRoot, data, networkOverride) {
17837
18001
  const isMainnet = name === "bsc-mainnet";
17838
18002
  const minBnb = isTestnet ? BSC_TESTNET_MIN_BNB : isMainnet ? BSC_MAINNET_MIN_BNB : 0;
17839
18003
  const minBnbWei = BigInt(Math.round(minBnb * 1e6)) * 10n ** 12n;
17840
- const faucetHint = isTestnet ? ` \u2014 faucets: ${BSC_TESTNET_FAUCET_URLS3.join(", ")}` : "";
18004
+ const bnbFaucetHint = isTestnet ? ` \u2014 ${tbnbFaucetHint3(address)}` : "";
18005
+ const uFaucetHint = isTestnet ? ` \u2014 $U faucet: ${BSC_TESTNET_U_FAUCET_URL3}` : "";
17841
18006
  const bnbRaw = await readNativeBalanceRaw(address, name);
17842
18007
  const reserve = ERC8183_SUBMIT_GAS_RESERVE_BNB;
17843
18008
  const reserveHint = ` (each on-chain action reserves \u2248 ${reserve} BNB worst-case)`;
@@ -17858,7 +18023,7 @@ async function checkBalances(projectRoot, data, networkOverride) {
17858
18023
  out.push({
17859
18024
  name: "wallet BNB balance",
17860
18025
  status: WARN,
17861
- detail: `${bnbRaw} wei @ ${address} \u2014 need \u2265 ${minBnb} BNB on ${name} for 8183 escrow / ERC-8004 register${reserveHint}${faucetHint}`
18026
+ detail: `${bnbRaw} wei @ ${address} \u2014 need \u2265 ${minBnb} BNB on ${name} for 8183 escrow / ERC-8004 register${reserveHint}${bnbFaucetHint}`
17862
18027
  });
17863
18028
  }
17864
18029
  const uToken = net2.tokens.U;
@@ -17884,7 +18049,7 @@ async function checkBalances(projectRoot, data, networkOverride) {
17884
18049
  out.push({
17885
18050
  name: "wallet U balance",
17886
18051
  status: WARN,
17887
- detail: `${uRaw} raw @ ${address} \u2014 need \u2265 ${minU} U on ${name} for one auto-topup chunk${faucetHint}`
18052
+ detail: `${uRaw} raw @ ${address} \u2014 need \u2265 ${minU} U on ${name} for one auto-topup chunk${uFaucetHint}`
17888
18053
  });
17889
18054
  }
17890
18055
  return out;
@@ -18033,11 +18198,7 @@ async function checkDeployTools(data, destination) {
18033
18198
  });
18034
18199
  if (destination === "platform") {
18035
18200
  const out = [
18036
- {
18037
- name: "deploy: bnbagent-deploy",
18038
- status: INFO,
18039
- detail: "[deploy].destination='platform' also delegates to bnbagent-deploy (bunx); `bag deploy prepare` verifies it."
18040
- },
18201
+ emit2(await checkBunx()),
18041
18202
  {
18042
18203
  name: "deploy: AWS credentials",
18043
18204
  status: INFO,
@@ -18067,6 +18228,49 @@ async function checkDeployTools(data, destination) {
18067
18228
  }
18068
18229
  return (await deployChecks()).map(emit2);
18069
18230
  }
18231
+ async function checkPlatformZipBundle(data, destination, projectRootArg2) {
18232
+ if (destination !== "platform" || platformPackagingRequiresContainer(data)) {
18233
+ return [];
18234
+ }
18235
+ let projectRoot = projectRootArg2;
18236
+ const parent = path39.dirname(projectRoot);
18237
+ if (isFile17(path39.join(parent, "agent", "studio.toml"))) {
18238
+ projectRoot = parent;
18239
+ }
18240
+ const agentDir = path39.join(projectRoot, "agent");
18241
+ if (!isFile17(path39.join(agentDir, "studio.toml"))) {
18242
+ return [];
18243
+ }
18244
+ if (!fs39.existsSync(path39.join(agentDir, "node_modules"))) {
18245
+ return [
18246
+ {
18247
+ name: "deploy: zip bundle",
18248
+ status: INFO,
18249
+ detail: "skipped \u2014 dependencies not installed yet (run `pnpm install`); re-run `bag doctor` to dry-run the zip bundle."
18250
+ }
18251
+ ];
18252
+ }
18253
+ const stack = tableOf14(data, "stack");
18254
+ const faces = stackFaces(stack, tableOf14(data, "payments"));
18255
+ try {
18256
+ await dryRunBundle(agentDir, { protocols: faces });
18257
+ } catch (exc) {
18258
+ return [
18259
+ {
18260
+ name: "deploy: zip bundle",
18261
+ status: WARN,
18262
+ detail: errMsg3(exc)
18263
+ }
18264
+ ];
18265
+ }
18266
+ return [
18267
+ {
18268
+ name: "deploy: zip bundle",
18269
+ status: PASS,
18270
+ detail: "esbuild dry run OK \u2014 the agent bundles for the platform ZIP runtime."
18271
+ }
18272
+ ];
18273
+ }
18070
18274
  function checkAgentsMdSkillTrigger(projectRoot) {
18071
18275
  const ws = findStudioWorkspaceRoot4(projectRoot);
18072
18276
  if (ws === null) {
@@ -18245,9 +18449,9 @@ import {
18245
18449
  updateServiceEndpoint as updateServiceEndpoint2
18246
18450
  } from "@bnbagent/studio-runtime/erc8004";
18247
18451
  import {
18248
- BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS4,
18249
18452
  fromRaw as fromRaw4,
18250
- getNetwork as getNetwork10
18453
+ getNetwork as getNetwork10,
18454
+ tbnbFaucetHint as tbnbFaucetHint4
18251
18455
  } from "@bnbagent/studio-runtime/networks";
18252
18456
  import * as walletRt6 from "@bnbagent/studio-runtime/wallet";
18253
18457
  import { Option as Option5 } from "commander";
@@ -18409,8 +18613,7 @@ async function precheckRegisterGas(wallet, network) {
18409
18613
  if (balance >= REGISTER_MIN_BNB) {
18410
18614
  return null;
18411
18615
  }
18412
- const faucet = BSC_TESTNET_FAUCET_URLS4[0];
18413
- return `ERC-8004 register needs gas to broadcast, but ${wallet.address} holds only ${balance} BNB on ${network} (need ~${REGISTER_MIN_BNB}). Fund a little tBNB and retry. Faucet: ${faucet}`;
18616
+ return `ERC-8004 register needs gas to broadcast, but ${wallet.address} holds only ${balance} BNB on ${network} (need ~${REGISTER_MIN_BNB}). Fund a little tBNB and retry \u2014 ${tbnbFaucetHint4(wallet.address)}`;
18414
18617
  }
18415
18618
  function syncAgentRegistry(agentId, op) {
18416
18619
  try {
@@ -19360,7 +19563,7 @@ async function promptInstallScope() {
19360
19563
  }
19361
19564
  function printNextSteps2() {
19362
19565
  printOut(
19363
- "\nNext: `bag init my-agent` to scaffold a single seller agent project.\nIn your IDE, type /bnbagent-studio to drive any studio task \u2014 the one\ninstalled skill routes everything (its playbooks load on demand).\nSee `bag --help` for the full command surface, or https://github.com/bnb-chain/bnbagent-studio for docs."
19566
+ "\nNext: `bag init myagent` to scaffold a single seller agent project.\nIn your IDE, type /bnbagent-studio to drive any studio task \u2014 the one\ninstalled skill routes everything (its playbooks load on demand).\nSee `bag --help` for the full command surface, or https://github.com/bnb-chain/bnbagent-studio for docs."
19364
19567
  );
19365
19568
  }
19366
19569
  async function installInteractive(flags) {
@@ -21042,7 +21245,7 @@ function buildProgram() {
21042
21245
  return program;
21043
21246
  }
21044
21247
  function cliVersion() {
21045
- return "0.0.8";
21248
+ return studioCliVersion();
21046
21249
  }
21047
21250
 
21048
21251
  // src/cli/updateCheck.ts
@@ -21169,6 +21372,10 @@ async function main(argv) {
21169
21372
  if (err instanceof CliExit) {
21170
21373
  return err.code;
21171
21374
  }
21375
+ if (err instanceof Error && err.name === "PromptCancelled") {
21376
+ process.stderr.write("cancelled.\n");
21377
+ return 130;
21378
+ }
21172
21379
  if (isCommanderExit(err)) {
21173
21380
  return err.exitCode;
21174
21381
  }