@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.
- package/LICENSE +201 -0
- package/README.md +2 -2
- package/dist/_agentcoreName-DZDWEYD3.js +0 -0
- package/dist/_twak-4XF4H5PL.js +0 -0
- package/dist/bag.js +577 -370
- package/dist/chunk-RO726HJG.js +0 -0
- package/dist/{chunk-YFEM4564.js → chunk-TTPOH453.js} +79 -37
- package/dist/chunk-U7IDQ3K5.js +0 -0
- package/dist/{deployCli-NJFCWBSF.js → deployCli-K55GXDVO.js} +1 -1
- package/package.json +11 -12
- package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +20 -21
- package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +36 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
- package/recipes/runtimes/agentcore/recipe.toml +3 -3
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +25 -23
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +16 -12
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +72 -393
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +160 -43
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/sellerCore.ts.tmpl +504 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
- package/recipes/runtimes/azure-foundry/recipe.toml +19 -11
- package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +6 -4
- package/skills/bnbagent-studio.md +2 -2
- package/skills/references/bnbagent-studio-adding-to-project.md +1 -1
- package/skills/references/bnbagent-studio-buying-from-bazaar.md +1 -1
- package/skills/references/bnbagent-studio-operating.md +4 -4
- package/skills/references/bnbagent-studio-scaffolding-agent.md +4 -4
- package/skills/references/bnbagent-studio-selling-via-8183.md +3 -3
- package/skills/references/bnbagent-studio-selling-via-b402.md +2 -2
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +1 -1
- package/skills/references/bnbagent-studio-use-azure-foundry.md +3 -3
- package/skills/references/bnbagent-studio-use-bnb-trial.md +1 -1
- package/skills/references/bnbagent-studio-wiring-llm-tools.md +3 -3
- package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +0 -347
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +0 -422
- 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-
|
|
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-
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (!
|
|
580
|
+
if (!fs4.existsSync(file)) {
|
|
516
581
|
return { schema_version: SCHEMA_VERSION, projects: [] };
|
|
517
582
|
}
|
|
518
583
|
let text2;
|
|
519
584
|
try {
|
|
520
|
-
text2 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
575
|
-
|
|
639
|
+
path3.join(projectRoot, "app", "agent"),
|
|
640
|
+
path3.join(projectRoot, "agent")
|
|
576
641
|
]) {
|
|
577
|
-
if (isFile(
|
|
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
|
-
|
|
586
|
-
|
|
587
|
-
|
|
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(
|
|
663
|
+
return parse(fs4.readFileSync(studioToml, "utf-8"));
|
|
599
664
|
}
|
|
600
665
|
function scanWalletAddress(projectRoot) {
|
|
601
|
-
const walletsDir =
|
|
666
|
+
const walletsDir = path3.join(projectRoot, ".studio", "wallets");
|
|
602
667
|
if (!isDir(walletsDir)) {
|
|
603
668
|
return null;
|
|
604
669
|
}
|
|
605
|
-
for (const child of
|
|
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(`~${
|
|
621
|
-
return
|
|
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
|
|
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 ||
|
|
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 =
|
|
653
|
-
|
|
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 (
|
|
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
|
|
1040
|
-
import * as
|
|
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 ?
|
|
1118
|
-
if (
|
|
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 =
|
|
1188
|
+
const parent = path4.dirname(current);
|
|
1124
1189
|
if (parent === current) {
|
|
1125
1190
|
return null;
|
|
1126
1191
|
}
|
|
1127
|
-
if (
|
|
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
|
|
1204
|
-
import * as
|
|
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
|
|
1210
|
-
import * as
|
|
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 =
|
|
1214
|
-
if (!
|
|
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
|
-
|
|
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 =
|
|
1498
|
-
const text2 =
|
|
1499
|
-
|
|
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 =
|
|
1611
|
+
const ledgerPath = path6.join(root, ".studio", "spend-ledger.json");
|
|
1547
1612
|
printOut("");
|
|
1548
1613
|
printOut("spend ledger (.studio/spend-ledger.json):");
|
|
1549
|
-
if (!
|
|
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(
|
|
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
|
|
1647
|
-
import * as
|
|
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
|
|
1659
|
-
import * as
|
|
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 =
|
|
1732
|
+
let dir = path7.dirname(fileURLToPath2(import.meta.url));
|
|
1668
1733
|
for (; ; ) {
|
|
1669
|
-
const candidate =
|
|
1670
|
-
const packageJson =
|
|
1671
|
-
if (
|
|
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 =
|
|
1674
|
-
const pkg = JSON.parse(
|
|
1675
|
-
return typeof pkg.version === "string" ? { root:
|
|
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 =
|
|
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(
|
|
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 =
|
|
1774
|
+
const srcDir = path7.join(sourceRoot, "src");
|
|
1710
1775
|
const walk = (dir) => {
|
|
1711
1776
|
let names;
|
|
1712
1777
|
try {
|
|
1713
|
-
names =
|
|
1778
|
+
names = fs8.readdirSync(dir).sort();
|
|
1714
1779
|
} catch {
|
|
1715
1780
|
return;
|
|
1716
1781
|
}
|
|
1717
1782
|
for (const name of names) {
|
|
1718
|
-
const full =
|
|
1719
|
-
const st =
|
|
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 =
|
|
1729
|
-
if (
|
|
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(
|
|
1734
|
-
h.update(
|
|
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
|
-
|
|
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
|
-
|
|
1750
|
-
|
|
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(
|
|
1824
|
+
return crypto.createHash("sha256").update(fs8.readFileSync(p)).digest("hex");
|
|
1760
1825
|
}
|
|
1761
1826
|
function rewriteDepToTarball(agentDir, pkgName, tarballName) {
|
|
1762
|
-
const pkgJsonPath =
|
|
1763
|
-
if (!
|
|
1827
|
+
const pkgJsonPath = path7.join(agentDir, "package.json");
|
|
1828
|
+
if (!fs8.existsSync(pkgJsonPath)) {
|
|
1764
1829
|
return;
|
|
1765
1830
|
}
|
|
1766
|
-
const pkg = JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
1863
|
+
for (const name of fs8.readdirSync(vendorDir)) {
|
|
1799
1864
|
if (name.startsWith(prefix) && name.endsWith(".tgz")) {
|
|
1800
|
-
|
|
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 &&
|
|
1820
|
-
if (!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 =
|
|
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(
|
|
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 =
|
|
1933
|
+
const workspacePath = path7.join(workspaceRoot, "pnpm-workspace.yaml");
|
|
1869
1934
|
const workspaceDoc = parseYaml(
|
|
1870
|
-
|
|
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 =
|
|
1875
|
-
const pkg = JSON.parse(
|
|
1876
|
-
const relVendor =
|
|
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
|
-
|
|
1886
|
-
const agentWorkspacePath =
|
|
1950
|
+
fs8.writeFileSync(workspacePath, stringifyYaml(workspace));
|
|
1951
|
+
const agentWorkspacePath = path7.join(agentDir, "pnpm-workspace.yaml");
|
|
1887
1952
|
const agentWorkspaceDoc = parseYaml(
|
|
1888
|
-
|
|
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
|
-
|
|
1961
|
+
fs8.writeFileSync(agentWorkspacePath, stringifyYaml(agentWorkspace));
|
|
1897
1962
|
pkg.pnpm = { ...pkg.pnpm ?? {}, overrides };
|
|
1898
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1966
|
-
opts.output ??
|
|
2030
|
+
const outputDir = path8.resolve(
|
|
2031
|
+
opts.output ?? path8.join(workspaceRoot, "dist")
|
|
1967
2032
|
);
|
|
1968
|
-
|
|
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 =
|
|
1972
|
-
const stagedWorkspace =
|
|
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 =
|
|
1979
|
-
const stagedAgent =
|
|
1980
|
-
const archivePath =
|
|
1981
|
-
|
|
1982
|
-
|
|
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
|
-
|
|
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 &&
|
|
2092
|
+
if (found !== null && fs9.existsSync(path8.join(found, "studio.toml"))) {
|
|
2028
2093
|
return found;
|
|
2029
2094
|
}
|
|
2030
|
-
return
|
|
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
|
|
2102
|
+
return path8.basename(found) === "app" ? path8.dirname(found) : found;
|
|
2038
2103
|
}
|
|
2039
2104
|
function readProjectName(agentRoot2) {
|
|
2040
|
-
const cfg = loadStudioToml2(
|
|
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 =
|
|
2054
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
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 =
|
|
2058
|
-
const excludedOutput = outputDir ?
|
|
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 =
|
|
2128
|
+
const name = path8.basename(src);
|
|
2064
2129
|
if (src !== source && excludedName(name)) {
|
|
2065
2130
|
return;
|
|
2066
2131
|
}
|
|
2067
|
-
const stat =
|
|
2132
|
+
const stat = fs9.lstatSync(src);
|
|
2068
2133
|
if (stat.isSymbolicLink()) {
|
|
2069
|
-
const link =
|
|
2070
|
-
const lexicalTarget =
|
|
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 =
|
|
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 ${
|
|
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
|
-
|
|
2082
|
-
|
|
2146
|
+
fs9.mkdirSync(path8.dirname(dst), { recursive: true });
|
|
2147
|
+
fs9.symlinkSync(link, dst);
|
|
2083
2148
|
return;
|
|
2084
2149
|
}
|
|
2085
2150
|
if (stat.isDirectory()) {
|
|
2086
|
-
|
|
2087
|
-
for (const child of
|
|
2088
|
-
copy(
|
|
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
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
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 =
|
|
2103
|
-
const target =
|
|
2104
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
2201
|
+
const root = path8.resolve(stagedWorkspace);
|
|
2137
2202
|
const walk = (dir) => {
|
|
2138
|
-
for (const name of
|
|
2139
|
-
const full =
|
|
2140
|
-
const rel =
|
|
2141
|
-
const stat =
|
|
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 =
|
|
2145
|
-
const target =
|
|
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" &&
|
|
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 =
|
|
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
|
-
|
|
2286
|
+
fs9.writeFileSync(path8.join(stagedWorkspace, "INSTALL.md"), lines.join("\n"));
|
|
2222
2287
|
}
|
|
2223
2288
|
|
|
2224
2289
|
// src/cli/config.ts
|
|
2225
|
-
import * as
|
|
2226
|
-
import * as
|
|
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 =
|
|
2493
|
-
const text2 =
|
|
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(
|
|
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 =
|
|
2532
|
-
const text2 =
|
|
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
|
-
|
|
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(
|
|
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
|
|
2649
|
-
import * as
|
|
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
|
|
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 =
|
|
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(
|
|
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 [
|
|
2699
|
-
if (isFile2(
|
|
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 =
|
|
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(
|
|
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
|
|
2778
|
-
import * as
|
|
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) ??
|
|
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 =
|
|
2957
|
+
const p = path11.join(agentRootOf(root), "studio.toml");
|
|
2893
2958
|
try {
|
|
2894
|
-
if (!
|
|
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
|
|
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 =
|
|
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
|
|
3104
|
-
import * as
|
|
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
|
|
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
|
|
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
|
|
3191
|
+
return fs13.realpathSync(p);
|
|
3127
3192
|
} catch {
|
|
3128
|
-
return
|
|
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
|
|
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 =
|
|
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(
|
|
3209
|
+
sources.push(path12.join(agentRoot2, ".env.local"));
|
|
3145
3210
|
}
|
|
3146
|
-
sources.push(
|
|
3211
|
+
sources.push(path12.join(ws, ".bag-env-stash", ".env.local"));
|
|
3147
3212
|
for (const src of sources) {
|
|
3148
|
-
if (!isFile3(src) ||
|
|
3213
|
+
if (!isFile3(src) || path12.resolve(src) === path12.resolve(target)) {
|
|
3149
3214
|
continue;
|
|
3150
3215
|
}
|
|
3151
|
-
if (
|
|
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
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
3206
|
-
const target =
|
|
3207
|
-
const 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
|
|
3210
|
-
const sub =
|
|
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
|
-
|
|
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 +
|
|
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 =
|
|
3235
|
-
const tomlPath =
|
|
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 =
|
|
3302
|
+
const text2 = fs13.readFileSync(tomlPath, "utf-8");
|
|
3238
3303
|
const updated = updateSection(text2, "wallet", { keystore_dir: rel });
|
|
3239
3304
|
if (updated !== text2) {
|
|
3240
|
-
|
|
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
|
-
|
|
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
|
|
3257
|
-
const f =
|
|
3258
|
-
if (
|
|
3259
|
-
|
|
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 =
|
|
3264
|
-
const b =
|
|
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
|
-
|
|
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
|
|
3294
|
-
import * as
|
|
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
|
-
|
|
3338
|
-
|
|
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) ??
|
|
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(
|
|
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) ??
|
|
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) ??
|
|
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(
|
|
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)
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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(
|
|
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)
|
|
8171
|
+
if (destination === "self" && runtime === "azure-foundry" && (hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces))) {
|
|
8076
8172
|
printErr(
|
|
8077
|
-
"error: azure-foundry supports
|
|
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
|
-
|
|
8406
|
-
//
|
|
8407
|
-
//
|
|
8408
|
-
|
|
8409
|
-
//
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
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 {
|
|
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)
|
|
9255
|
-
|
|
9256
|
-
|
|
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
|
-
"
|
|
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
|
-
}
|
|
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/
|
|
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/
|
|
9897
|
+
return "app/agent/src/unifiedMain.ts = X402-only runtime entrypoint (build your value here)";
|
|
9762
9898
|
}
|
|
9763
|
-
return "app/agent/src/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
|
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/${
|
|
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) &&
|
|
11590
|
-
const blocking = target
|
|
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 {
|
|
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
|
|
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.
|
|
13526
|
-
details: {
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
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 =
|
|
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
|
|
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}${
|
|
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${
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
}
|