@bnbagent/studio-cli 0.0.10 → 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 +317 -124
- 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 {
|
|
@@ -454,8 +458,8 @@ function packageRoot() {
|
|
|
454
458
|
}
|
|
455
459
|
}
|
|
456
460
|
function studioCliVersion() {
|
|
457
|
-
if ("0.0.
|
|
458
|
-
return "0.0.
|
|
461
|
+
if ("0.0.11-alpha.1") {
|
|
462
|
+
return "0.0.11-alpha.1";
|
|
459
463
|
}
|
|
460
464
|
const file = path2.join(packageRoot(), "package.json");
|
|
461
465
|
const pkg = JSON.parse(fs3.readFileSync(file, "utf-8"));
|
|
@@ -491,15 +495,34 @@ import { parse, stringify } from "smol-toml";
|
|
|
491
495
|
|
|
492
496
|
// src/cli/utils/prompt.ts
|
|
493
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
|
+
}
|
|
494
519
|
async function promptUser(question) {
|
|
495
520
|
const rl = readline.createInterface({
|
|
496
521
|
input: process.stdin,
|
|
497
522
|
output: process.stdout
|
|
498
523
|
});
|
|
499
524
|
try {
|
|
500
|
-
return await rl
|
|
501
|
-
} catch {
|
|
502
|
-
return "";
|
|
525
|
+
return await ask(rl, question);
|
|
503
526
|
} finally {
|
|
504
527
|
rl.close();
|
|
505
528
|
}
|
|
@@ -510,9 +533,7 @@ async function promptUserStderr(question) {
|
|
|
510
533
|
output: process.stderr
|
|
511
534
|
});
|
|
512
535
|
try {
|
|
513
|
-
return await rl
|
|
514
|
-
} catch {
|
|
515
|
-
return "";
|
|
536
|
+
return await ask(rl, question);
|
|
516
537
|
} finally {
|
|
517
538
|
rl.close();
|
|
518
539
|
}
|
|
@@ -526,9 +547,7 @@ async function promptHidden(question) {
|
|
|
526
547
|
terminal: false
|
|
527
548
|
});
|
|
528
549
|
try {
|
|
529
|
-
return await rl
|
|
530
|
-
} catch {
|
|
531
|
-
return "";
|
|
550
|
+
return await ask(rl, "");
|
|
532
551
|
} finally {
|
|
533
552
|
rl.close();
|
|
534
553
|
process.stderr.write("\n");
|
|
@@ -3455,13 +3474,13 @@ function unavailableProvidersForProject(root) {
|
|
|
3455
3474
|
const cfg = loadStudioToml6(path13.join(agentRoot2, "studio.toml"));
|
|
3456
3475
|
runtime = text(tableOf3(cfg, "stack").runtime) ?? "agentcore";
|
|
3457
3476
|
const faces = stackFaces(tableOf3(cfg, "stack"), tableOf3(cfg, "payments"));
|
|
3458
|
-
azureProtocolUnsupported = !hasA2aFace(faces)
|
|
3477
|
+
azureProtocolUnsupported = hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces);
|
|
3459
3478
|
} catch {
|
|
3460
3479
|
return {};
|
|
3461
3480
|
}
|
|
3462
3481
|
if (runtime === "azure-foundry") {
|
|
3463
3482
|
const reason = "this project uses a different container adapter; scaffold an agentcore project before selecting this provider";
|
|
3464
|
-
const azureProtocolReason = "Azure Foundry deploy
|
|
3483
|
+
const azureProtocolReason = "Azure Foundry deploy supports A2A and X402 seller projects; use AgentCore for MCP";
|
|
3465
3484
|
return {
|
|
3466
3485
|
aws: reason,
|
|
3467
3486
|
...azureProtocolUnsupported ? {
|
|
@@ -4488,22 +4507,23 @@ var checkEntrypointAndDockerfile = async (root, _target) => {
|
|
|
4488
4507
|
const findings = [];
|
|
4489
4508
|
const cfg = loadStudioCfg(deployWorkspaceRoot(root));
|
|
4490
4509
|
const faces = stackFaces(tableOf4(cfg, "stack"), tableOf4(cfg, "payments"));
|
|
4491
|
-
if (!hasA2aFace(faces)
|
|
4510
|
+
if (hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces)) {
|
|
4492
4511
|
return [
|
|
4493
4512
|
{
|
|
4494
4513
|
level: "CRITICAL",
|
|
4495
4514
|
name: "azure_protocol_supported",
|
|
4496
|
-
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.",
|
|
4497
4516
|
details: { faces }
|
|
4498
4517
|
}
|
|
4499
4518
|
];
|
|
4500
4519
|
}
|
|
4501
|
-
const
|
|
4520
|
+
const entryCandidates = ["src/unifiedMain.ts", "src/foundryMain.ts"];
|
|
4521
|
+
const entry = entryCandidates.find((c2) => isFile6(path17.join(agentRoot2, c2))) ?? entryCandidates[0];
|
|
4502
4522
|
if (!isFile6(path17.join(agentRoot2, entry))) {
|
|
4503
4523
|
findings.push({
|
|
4504
4524
|
level: "CRITICAL",
|
|
4505
4525
|
name: "azure_agent_entrypoint",
|
|
4506
|
-
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\`.`,
|
|
4507
4527
|
details: { entrypoint: entry }
|
|
4508
4528
|
});
|
|
4509
4529
|
}
|
|
@@ -4606,7 +4626,11 @@ import * as walletRt2 from "@bnbagent/studio-runtime/wallet";
|
|
|
4606
4626
|
import { generateText } from "ai";
|
|
4607
4627
|
|
|
4608
4628
|
// src/cli/_pieverseHelpers.ts
|
|
4609
|
-
import {
|
|
4629
|
+
import {
|
|
4630
|
+
BSC_TESTNET_U_FAUCET_URL,
|
|
4631
|
+
fromRaw as fromRaw2,
|
|
4632
|
+
getNetwork as getNetwork3
|
|
4633
|
+
} from "@bnbagent/studio-runtime/networks";
|
|
4610
4634
|
import {
|
|
4611
4635
|
siweLogin
|
|
4612
4636
|
} from "@bnbagent/studio-runtime/pieverse";
|
|
@@ -4659,9 +4683,7 @@ function printUBalanceShortfall(walletAddress, currentRaw, neededRaw, neededUsd,
|
|
|
4659
4683
|
` swap on PancakeSwap: https://pancakeswap.finance/swap?outputCurrency=${u.address}`
|
|
4660
4684
|
);
|
|
4661
4685
|
} else {
|
|
4662
|
-
printErr(
|
|
4663
|
-
" testnet U faucet URL is TBD \u2014 see docs/guides/pieverse-integration.md \xA76"
|
|
4664
|
-
);
|
|
4686
|
+
printErr(` testnet U faucet: ${BSC_TESTNET_U_FAUCET_URL}`);
|
|
4665
4687
|
}
|
|
4666
4688
|
}
|
|
4667
4689
|
function writeEnvLocal(key, value, envPath = ".env.local") {
|
|
@@ -6450,6 +6472,7 @@ import {
|
|
|
6450
6472
|
findProjectRoot as findProjectRoot3,
|
|
6451
6473
|
loadStudioToml as loadStudioToml10
|
|
6452
6474
|
} from "@bnbagent/studio-runtime/config";
|
|
6475
|
+
import { tbnbFaucetHint as tbnbFaucetHint2 } from "@bnbagent/studio-runtime/networks";
|
|
6453
6476
|
import { buildPolicy, buildWallet } from "@bnbagent/studio-runtime/wallet";
|
|
6454
6477
|
|
|
6455
6478
|
// src/cli/walletSession.ts
|
|
@@ -6467,8 +6490,8 @@ import {
|
|
|
6467
6490
|
import { auditedOp as auditedOp2 } from "@bnbagent/studio-runtime/audit";
|
|
6468
6491
|
import { loadStudioToml as loadStudioToml9 } from "@bnbagent/studio-runtime/config";
|
|
6469
6492
|
import {
|
|
6470
|
-
BSC_TESTNET_FAUCET_URLS,
|
|
6471
6493
|
getNetwork as getNetwork5,
|
|
6494
|
+
tbnbFaucetHint,
|
|
6472
6495
|
toRaw as toRaw2
|
|
6473
6496
|
} from "@bnbagent/studio-runtime/networks";
|
|
6474
6497
|
import { writePrivate } from "@bnbagent/studio-runtime/secretWrite";
|
|
@@ -6538,7 +6561,7 @@ async function requireAltanaAdminGas(ctx) {
|
|
|
6538
6561
|
}
|
|
6539
6562
|
if (balance !== 0n) return;
|
|
6540
6563
|
const symbol = ctx.networkName === "bsc-testnet" ? "tBNB" : "BNB";
|
|
6541
|
-
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.";
|
|
6542
6565
|
throw new Error(
|
|
6543
6566
|
`Altana admin wallet ${ctx.address} has 0 ${symbol} on ${ctx.networkName} and cannot pay gas for session administration.${funding}`
|
|
6544
6567
|
);
|
|
@@ -7000,6 +7023,14 @@ function projectNetwork(projectRoot) {
|
|
|
7000
7023
|
const dflt = net2 !== null && typeof net2 === "object" ? net2.default : void 0;
|
|
7001
7024
|
return dflt ? String(dflt) : "bsc-testnet";
|
|
7002
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
|
+
}
|
|
7003
7034
|
function twakProvider(projectRoot, walletCfg) {
|
|
7004
7035
|
return buildWallet(walletCfg, projectRoot, {
|
|
7005
7036
|
network: projectNetwork(projectRoot)
|
|
@@ -7193,6 +7224,8 @@ async function cmdNew(opts) {
|
|
|
7193
7224
|
printErr(
|
|
7194
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."
|
|
7195
7226
|
);
|
|
7227
|
+
} else {
|
|
7228
|
+
printNextAfterNew(projectRoot, provider.address);
|
|
7196
7229
|
}
|
|
7197
7230
|
return 0;
|
|
7198
7231
|
}
|
|
@@ -7232,6 +7265,7 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
7232
7265
|
const address = provider.address;
|
|
7233
7266
|
printOut(address);
|
|
7234
7267
|
persistAddress(projectRoot, address);
|
|
7268
|
+
printNextAfterNew(projectRoot, address);
|
|
7235
7269
|
return 0;
|
|
7236
7270
|
}
|
|
7237
7271
|
function ensureTwakCredentials(walletFile, homeDir) {
|
|
@@ -7964,6 +7998,44 @@ function enclosingProjectRoot(start) {
|
|
|
7964
7998
|
}
|
|
7965
7999
|
}
|
|
7966
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) {
|
|
7967
8039
|
const target = path23.resolve(process.cwd(), nameArg);
|
|
7968
8040
|
let projectName2 = path23.basename(target);
|
|
7969
8041
|
if (!projectName2) {
|
|
@@ -7972,6 +8044,14 @@ async function cmdInit(nameArg, opts) {
|
|
|
7972
8044
|
);
|
|
7973
8045
|
return 2;
|
|
7974
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
|
+
}
|
|
7975
8055
|
if (opts.protocols !== void 0 && opts.protocol !== void 0) {
|
|
7976
8056
|
printErr("error: pass either --protocols or --protocol, not both.");
|
|
7977
8057
|
return 2;
|
|
@@ -8062,7 +8142,9 @@ async function cmdInit(nameArg, opts) {
|
|
|
8062
8142
|
return 2;
|
|
8063
8143
|
}
|
|
8064
8144
|
if (fs24.existsSync(target) && !opts.force) {
|
|
8065
|
-
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
|
+
);
|
|
8066
8148
|
return 2;
|
|
8067
8149
|
}
|
|
8068
8150
|
if (opts.destination === "platform" && opts.network === "bsc-mainnet") {
|
|
@@ -8086,13 +8168,20 @@ async function cmdInit(nameArg, opts) {
|
|
|
8086
8168
|
destination = "self";
|
|
8087
8169
|
runtime = "agentcore";
|
|
8088
8170
|
}
|
|
8089
|
-
if (destination === "self" && runtime === "azure-foundry" && (!hasA2aFace(faces)
|
|
8171
|
+
if (destination === "self" && runtime === "azure-foundry" && (hasMcpFace(faces) || !hasA2aFace(faces) && !hasX402Face(faces))) {
|
|
8090
8172
|
printErr(
|
|
8091
|
-
"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."
|
|
8092
8174
|
);
|
|
8093
8175
|
return 2;
|
|
8094
8176
|
}
|
|
8095
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
|
+
}
|
|
8096
8185
|
fs24.rmSync(target, { recursive: true, force: true });
|
|
8097
8186
|
}
|
|
8098
8187
|
if (destination === "platform") {
|
|
@@ -8410,17 +8499,18 @@ function scaffold(target, name, o) {
|
|
|
8410
8499
|
const isContainer = packaging === "container";
|
|
8411
8500
|
const mode = recipeModeOf(o.faces);
|
|
8412
8501
|
const stem2 = entryStemOf(o.faces);
|
|
8413
|
-
const a2aEntry = o.runtime === "azure-foundry" ? "dist/foundryMain.js" : "dist/main.js";
|
|
8414
8502
|
const runtimeCtx = {
|
|
8415
8503
|
PKG: AGENT_SRC,
|
|
8416
8504
|
TWAK_CLI_VERSION,
|
|
8417
8505
|
PNPM_VERSION: packageManagerVersion,
|
|
8418
8506
|
DEPLOYMENT_TYPE: isContainer ? "container" : "direct_code_deploy",
|
|
8419
|
-
|
|
8420
|
-
//
|
|
8421
|
-
//
|
|
8422
|
-
|
|
8423
|
-
//
|
|
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.
|
|
8424
8514
|
CONTAINER_PORT: o.runtime === "azure-foundry" ? "8088" : String(devPortOf(o.faces))
|
|
8425
8515
|
};
|
|
8426
8516
|
emitRecipe(agentRoot2, "agent", { context: runtimeCtx });
|
|
@@ -8786,10 +8876,11 @@ function renderAgentStudioToml(name, o) {
|
|
|
8786
8876
|
# Read by the Agent: it quotes the FIXED \`price\`, CLAMPS it to [min,max],
|
|
8787
8877
|
# freezes a short-TTL offer, and EIP-191 signs it \u2014 pricing is rule-based, the
|
|
8788
8878
|
# LLM never prices. price=0 is FREE and is supported by the canonical stack.
|
|
8789
|
-
currency = "${currencyAddr}" # $U token address \u2014 prefilled from [network].default
|
|
8790
|
-
|
|
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)
|
|
8791
8882
|
min_price = "0" # wei \u2014 clamp floor
|
|
8792
|
-
max_price = "" # wei \u2014 clamp ceiling; SET before going live
|
|
8883
|
+
max_price = "" # wei \u2014 clamp ceiling; empty = unbounded; SET before going live
|
|
8793
8884
|
quote_ttl_seconds = 900 # seconds a signed quote stays valid; SDK caps at 900 (~15min work window)
|
|
8794
8885
|
default_estimated_completion_seconds = 600
|
|
8795
8886
|
poll_interval_seconds = 30
|
|
@@ -8927,7 +9018,7 @@ function renderAgentReadme(name, faces, destination, walletKind2) {
|
|
|
8927
9018
|
const port = String(devPortOf(faces));
|
|
8928
9019
|
const x402Only = faces.length === 1 && hasX402Face(faces);
|
|
8929
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`";
|
|
8930
|
-
const filesA2a = `- \`src/
|
|
9021
|
+
const filesA2a = `- \`src/unifiedMain.ts\` \u2014 unified serving entrypoint (A2A on port 9000 + Foundry invocations on 8088).
|
|
8931
9022
|
- \`src/executor.ts\` \u2014 the SellerAgentExecutor: the negotiate + notify_funded A2A skills.
|
|
8932
9023
|
- \`src/agentCard.ts\` \u2014 the discoverable AgentCard (+ OAuth2/Cognito scheme).`;
|
|
8933
9024
|
const filesMcp = `- \`src/mcpMain.ts\` \u2014 MCP serving entrypoint (streamable HTTP on \`/mcp\`; deploy
|
|
@@ -9077,10 +9168,23 @@ async function resolveWalletKind(flagValue, isTty) {
|
|
|
9077
9168
|
);
|
|
9078
9169
|
return "evm-local";
|
|
9079
9170
|
}
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
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";
|
|
9084
9188
|
}
|
|
9085
9189
|
async function resolveLlmProviderForWallet(walletKind2, configuredProvider, valueSource, isTty) {
|
|
9086
9190
|
if (walletKind2 !== "altana") {
|
|
@@ -9263,12 +9367,22 @@ function readWalletAddress(studioToml) {
|
|
|
9263
9367
|
async function printFaucetHint(network, address) {
|
|
9264
9368
|
printOut("");
|
|
9265
9369
|
if (network === "bsc-testnet") {
|
|
9266
|
-
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");
|
|
9267
9375
|
printOut(`Your testnet wallet address: ${address}`);
|
|
9268
|
-
printOut("Fund it (free)
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
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}`);
|
|
9272
9386
|
printOut("(Faucets are needed only for paid models / on-chain settle.");
|
|
9273
9387
|
printOut(" The default `auto/free` LLM model and AgentCore deploy");
|
|
9274
9388
|
printOut(" do NOT require any funds.)");
|
|
@@ -9632,18 +9746,26 @@ function printMainTwakWalletWarning() {
|
|
|
9632
9746
|
);
|
|
9633
9747
|
}
|
|
9634
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
|
+
}
|
|
9635
9756
|
let key = ipfsKey;
|
|
9636
9757
|
if (key === void 0) {
|
|
9637
9758
|
key = (await promptUser(
|
|
9638
|
-
"
|
|
9759
|
+
"IPFS pinning-service write key/JWT (blank to skip, fill STORAGE_API_KEY later): "
|
|
9639
9760
|
)).trim();
|
|
9640
9761
|
}
|
|
9641
9762
|
if (key) {
|
|
9642
9763
|
setEnvVar(envPath, "STORAGE_API_KEY", key);
|
|
9643
9764
|
printOut("\u2713 STORAGE_API_KEY written to .studio/.env.local");
|
|
9644
|
-
}
|
|
9765
|
+
}
|
|
9766
|
+
if (!url || !key) {
|
|
9645
9767
|
printErr(
|
|
9646
|
-
"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."
|
|
9647
9769
|
);
|
|
9648
9770
|
}
|
|
9649
9771
|
}
|
|
@@ -9665,7 +9787,7 @@ function printCampaignIntro() {
|
|
|
9665
9787
|
);
|
|
9666
9788
|
}
|
|
9667
9789
|
function printTwakNotice(destination = "self") {
|
|
9668
|
-
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.";
|
|
9669
9791
|
printOut(
|
|
9670
9792
|
`
|
|
9671
9793
|
NOTE \u2014 wallet.kind = "twak" (Trust Wallet Agent Kit, CLI >= ${TWAK_CLI_VERSION}):
|
|
@@ -9772,9 +9894,9 @@ function entrypointHint(faces) {
|
|
|
9772
9894
|
return "app/agent/src/mcpMain.ts = MCP entrypoint (build your value here)";
|
|
9773
9895
|
}
|
|
9774
9896
|
if (faces.length === 1 && hasX402Face(faces)) {
|
|
9775
|
-
return "app/agent/src/
|
|
9897
|
+
return "app/agent/src/unifiedMain.ts = X402-only runtime entrypoint (build your value here)";
|
|
9776
9898
|
}
|
|
9777
|
-
return "app/agent/src/
|
|
9899
|
+
return "app/agent/src/unifiedMain.ts + executor.ts = A2A entrypoint (build your value here)";
|
|
9778
9900
|
}
|
|
9779
9901
|
function hasVendoredTarballs(agentDir) {
|
|
9780
9902
|
const vendor = path23.join(agentDir, "vendor");
|
|
@@ -9822,18 +9944,17 @@ function printCompactNextSteps(name, o = {}) {
|
|
|
9822
9944
|
" pnpm install # one-time: install the agent dependencies"
|
|
9823
9945
|
);
|
|
9824
9946
|
}
|
|
9947
|
+
printOut(" bag doctor # verify config + env before funding");
|
|
9948
|
+
printOut(" bag dev # run the Agent locally");
|
|
9825
9949
|
if (destination === "platform") {
|
|
9826
|
-
printOut(" bag dev # run the Agent locally");
|
|
9827
9950
|
printOut(
|
|
9828
9951
|
" bag deploy --provider bnb # Agent \u2192 managed platform (48h testnet trial)"
|
|
9829
9952
|
);
|
|
9830
9953
|
} else if (runtime === "azure-foundry") {
|
|
9831
|
-
printOut(" bag dev # run the Agent locally");
|
|
9832
9954
|
printOut(
|
|
9833
9955
|
" bag deploy --provider azure # Agent \u2192 Azure AI Foundry (delegated to bnbagent-deploy; browser login, no azd)"
|
|
9834
9956
|
);
|
|
9835
9957
|
} else {
|
|
9836
|
-
printOut(" agentcore dev # run the Agent locally on AgentCore");
|
|
9837
9958
|
printOut(" bag deploy --provider aws # Agent \u2192 AgentCore");
|
|
9838
9959
|
}
|
|
9839
9960
|
printOut("");
|
|
@@ -9963,19 +10084,7 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
9963
10084
|
printOut(" # is `auto/free` (Free) \u2014 no funding required to start.");
|
|
9964
10085
|
printOut(" bag llm activate");
|
|
9965
10086
|
printOut("");
|
|
9966
|
-
|
|
9967
|
-
" # 4. (optional) fund the wallet \u2014 only when you need paid model / deploy / publish:"
|
|
9968
|
-
);
|
|
9969
|
-
printOut(
|
|
9970
|
-
" # testnet: send testnet BNB (gas) + testnet U to the address above"
|
|
9971
|
-
);
|
|
9972
|
-
printOut(" # mainnet: swap a small amount via PancakeSwap:");
|
|
9973
|
-
printOut(
|
|
9974
|
-
" # https://pancakeswap.finance/swap?outputCurrency=0xcE24439F2D9C6a2289F741120FE202248B666666"
|
|
9975
|
-
);
|
|
9976
|
-
printOut(" # Then: bag llm topup --amount N (allocate paid credits)");
|
|
9977
|
-
printOut("");
|
|
9978
|
-
nextStep = 5;
|
|
10087
|
+
nextStep = 4;
|
|
9979
10088
|
} else {
|
|
9980
10089
|
const keyEnv = PROVIDER_KEY_ENV[provider];
|
|
9981
10090
|
if (keyEnv) {
|
|
@@ -9987,6 +10096,26 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
9987
10096
|
}
|
|
9988
10097
|
nextStep = 4;
|
|
9989
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("");
|
|
9990
10119
|
printOut(
|
|
9991
10120
|
` # ${nextStep}. review ERC-8183 pricing in studio.toml [payments.erc8183]`
|
|
9992
10121
|
);
|
|
@@ -9994,10 +10123,6 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
9994
10123
|
" # (price was selected at init; `bag config set payments.erc8183.price 0` explicitly switches to FREE)"
|
|
9995
10124
|
);
|
|
9996
10125
|
nextStep += 1;
|
|
9997
|
-
printOut(` # ${nextStep}. verify + run the agent locally`);
|
|
9998
|
-
printOut(" bag doctor");
|
|
9999
|
-
printOut(" bag dev");
|
|
10000
|
-
nextStep += 1;
|
|
10001
10126
|
if (destination === "platform") {
|
|
10002
10127
|
printOut(
|
|
10003
10128
|
` # ${nextStep}. deploy: app/agent \u2192 managed platform (48h testnet trial)`
|
|
@@ -10298,6 +10423,11 @@ function runtimeEnvKeysCore(cfg, resolvable) {
|
|
|
10298
10423
|
if (resolvable("RPC_URL")) {
|
|
10299
10424
|
keys.push("RPC_URL");
|
|
10300
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
|
+
}
|
|
10301
10431
|
for (const key of PAYMASTER_URL_ENV_KEYS) {
|
|
10302
10432
|
if (resolvable(key)) keys.push(key);
|
|
10303
10433
|
}
|
|
@@ -10306,8 +10436,7 @@ function runtimeEnvKeysCore(cfg, resolvable) {
|
|
|
10306
10436
|
if (resolvable(key)) keys.push(key);
|
|
10307
10437
|
}
|
|
10308
10438
|
}
|
|
10309
|
-
|
|
10310
|
-
if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
|
|
10439
|
+
if (X402_CAPABLE_RUNTIMES.has(runtimeName) && x402SellerUsesB402(cfg)) {
|
|
10311
10440
|
for (const key of B402_RUNTIME_KEYS) {
|
|
10312
10441
|
if (resolvable(key)) keys.push(key);
|
|
10313
10442
|
}
|
|
@@ -10413,8 +10542,12 @@ function agentFaces(workspaceRoot) {
|
|
|
10413
10542
|
const cfg = loadAgentToml2(workspaceRoot);
|
|
10414
10543
|
return stackFaces(tableOf9(cfg, "stack"), tableOf9(cfg, "payments"));
|
|
10415
10544
|
}
|
|
10416
|
-
function localEntryFile(faces) {
|
|
10417
|
-
|
|
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];
|
|
10418
10551
|
}
|
|
10419
10552
|
function defaultAgentPort(faces) {
|
|
10420
10553
|
return devPortOf(faces);
|
|
@@ -10786,11 +10919,11 @@ async function cmdDev(opts) {
|
|
|
10786
10919
|
const agentPort = opts.port ?? defaultAgentPort(faces);
|
|
10787
10920
|
const runtime = agentRuntime(workspaceRoot);
|
|
10788
10921
|
const container = Boolean(opts.container);
|
|
10789
|
-
const entryFile = localEntryFile(faces);
|
|
10922
|
+
const entryFile = localEntryFile(faces, agentDir);
|
|
10790
10923
|
const agentFile = path24.join(agentDir, entryFile);
|
|
10791
10924
|
if (!isFile10(agentFile)) {
|
|
10792
10925
|
printErr(
|
|
10793
|
-
`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.`
|
|
10794
10927
|
);
|
|
10795
10928
|
return 2;
|
|
10796
10929
|
}
|
|
@@ -10929,7 +11062,7 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10929
11062
|
printOut(
|
|
10930
11063
|
`bag dev: starting Agent in-process (\`tsx ${args.join(" ")}\` on :${agentPort}, no Docker \u2014 the entrypoint self-serves; cwd=${agentDir}, runner=${runner2})`
|
|
10931
11064
|
);
|
|
10932
|
-
if (runtime === RUNTIME_AZURE_FOUNDRY) {
|
|
11065
|
+
if (runtime === RUNTIME_AZURE_FOUNDRY && isFile10(path24.join(agentDir, "src/foundryMain.ts"))) {
|
|
10933
11066
|
printOut(
|
|
10934
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."
|
|
10935
11068
|
);
|
|
@@ -11102,7 +11235,10 @@ async function checkAgentPackagePresent(root, target) {
|
|
|
11102
11235
|
const cfg = loadAgentToml(root);
|
|
11103
11236
|
const faces = stackFaces(tableOf2(cfg, "stack"), tableOf2(cfg, "payments"));
|
|
11104
11237
|
const stem2 = entryStemOf(faces);
|
|
11105
|
-
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`];
|
|
11106
11242
|
if (stem2 === "dualMain") {
|
|
11107
11243
|
sourceEntries.push("src/mcpMain.ts");
|
|
11108
11244
|
}
|
|
@@ -11120,7 +11256,7 @@ async function checkAgentPackagePresent(root, target) {
|
|
|
11120
11256
|
}
|
|
11121
11257
|
];
|
|
11122
11258
|
}
|
|
11123
|
-
const distEntries = [`dist/${
|
|
11259
|
+
const distEntries = [`dist/${effectiveStem}.js`];
|
|
11124
11260
|
if (stem2 === "dualMain") {
|
|
11125
11261
|
distEntries.push("dist/mcpMain.js");
|
|
11126
11262
|
}
|
|
@@ -11600,12 +11736,12 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
|
|
|
11600
11736
|
}
|
|
11601
11737
|
const destination = String(tableOf2(cfg, "deploy").destination ?? "self");
|
|
11602
11738
|
const stackRuntime2 = String(tableOf2(cfg, "stack").runtime ?? "agentcore");
|
|
11603
|
-
if (rails.x402 && (free || credentials.complete) &&
|
|
11604
|
-
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;
|
|
11605
11741
|
out.push({
|
|
11606
11742
|
level: Level.WARNING,
|
|
11607
11743
|
name: "x402_forced_dormant_runtime",
|
|
11608
|
-
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.`,
|
|
11609
11745
|
details: { destination, target, stackRuntime: stackRuntime2 }
|
|
11610
11746
|
});
|
|
11611
11747
|
}
|
|
@@ -11656,7 +11792,7 @@ async function checkCommerceReady(root, target) {
|
|
|
11656
11792
|
return out;
|
|
11657
11793
|
}
|
|
11658
11794
|
async function checkDeployCliRunnable(_root, target) {
|
|
11659
|
-
if (target !== "agentcore") {
|
|
11795
|
+
if (target !== "agentcore" && target !== "platform" && target !== "platform-azure") {
|
|
11660
11796
|
return [];
|
|
11661
11797
|
}
|
|
11662
11798
|
const override = (process.env.BNBAGENT_DEPLOY_COMMAND ?? "").trim();
|
|
@@ -13062,7 +13198,11 @@ import {
|
|
|
13062
13198
|
findSubProjectRoot as findSubProjectRoot13,
|
|
13063
13199
|
loadStudioToml as loadStudioToml17
|
|
13064
13200
|
} from "@bnbagent/studio-runtime/config";
|
|
13065
|
-
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";
|
|
13066
13206
|
|
|
13067
13207
|
// src/cli/_deploy/checks/warning.ts
|
|
13068
13208
|
import * as crypto4 from "crypto";
|
|
@@ -13372,7 +13512,10 @@ var checkPlatformEntrypointPresent = async (root, _target) => {
|
|
|
13372
13512
|
const data = loadAgent(root);
|
|
13373
13513
|
const faces = stackFaces(tableOf11(data, "stack"), tableOf11(data, "payments"));
|
|
13374
13514
|
const stem2 = entryStemOf(faces);
|
|
13375
|
-
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`];
|
|
13376
13519
|
if (stem2 === "dualMain") filenames.push("mcpMain.ts");
|
|
13377
13520
|
const filename = filenames.find(
|
|
13378
13521
|
(candidate) => !fs35.existsSync(path34.join(agentRoot(root), "src", candidate))
|
|
@@ -13536,8 +13679,14 @@ var checkPlatformFundingHint = async (_root, _target) => [
|
|
|
13536
13679
|
{
|
|
13537
13680
|
level: Level.INFO,
|
|
13538
13681
|
name: "platform_funding_hint",
|
|
13539
|
-
message: `testnet trial \u2014 keep a little tBNB for gas and testnet $U for commerce.
|
|
13540
|
-
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
|
+
}
|
|
13541
13690
|
}
|
|
13542
13691
|
];
|
|
13543
13692
|
var criticalChecks = [
|
|
@@ -13546,6 +13695,7 @@ var criticalChecks = [
|
|
|
13546
13695
|
checkPlatformTestnetOnly,
|
|
13547
13696
|
checkPlatformSlugValid,
|
|
13548
13697
|
checkPlatformLoggedIn,
|
|
13698
|
+
checkDeployCliRunnable,
|
|
13549
13699
|
checkPlatformDockerAvailable,
|
|
13550
13700
|
checkPlatformStorageEndpoint,
|
|
13551
13701
|
checkTwakCustomContractsUnsupported,
|
|
@@ -14308,7 +14458,7 @@ async function platformAgent(opts) {
|
|
|
14308
14458
|
const root = opts.root;
|
|
14309
14459
|
const backend = opts.backend ?? "aws";
|
|
14310
14460
|
const isTty = opts.isTty ?? stdinIsTty;
|
|
14311
|
-
const
|
|
14461
|
+
const ask2 = opts.promptUser ?? promptUser;
|
|
14312
14462
|
warn(
|
|
14313
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.`
|
|
14314
14464
|
);
|
|
@@ -14317,12 +14467,6 @@ async function platformAgent(opts) {
|
|
|
14317
14467
|
const cfg2 = loadAgentCfg(root);
|
|
14318
14468
|
const faces2 = stackFaces(tableOf12(cfg2, "stack"), tableOf12(cfg2, "payments"));
|
|
14319
14469
|
const protocol2 = nativeProtocolOf(faces2);
|
|
14320
|
-
if (hasX402Face(faces2)) {
|
|
14321
|
-
warn(
|
|
14322
|
-
"error: x402 publication is not supported on the managed Azure backend. No build or upload was started."
|
|
14323
|
-
);
|
|
14324
|
-
return 1;
|
|
14325
|
-
}
|
|
14326
14470
|
const runtimeProfile = protocol2 === "A2A" ? "foundry-responses-v1" : "foundry-invocations-v1";
|
|
14327
14471
|
const capability = await platformCmd(["capabilities"], { json: true });
|
|
14328
14472
|
const platform = isJsonObject(capability.data.platform) ? capability.data.platform : {};
|
|
@@ -14336,6 +14480,12 @@ async function platformAgent(opts) {
|
|
|
14336
14480
|
);
|
|
14337
14481
|
return capability.code || 1;
|
|
14338
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
|
+
}
|
|
14339
14489
|
}
|
|
14340
14490
|
const campaignProbe = opts.campaignActive ?? (async () => null);
|
|
14341
14491
|
const trialRes = await platformCmd(["trial"], { json: true });
|
|
@@ -14364,7 +14514,7 @@ async function platformAgent(opts) {
|
|
|
14364
14514
|
const rc = await termsConsentGate(root, {
|
|
14365
14515
|
acceptRisk: opts.acceptRisk ?? false,
|
|
14366
14516
|
isTty,
|
|
14367
|
-
promptUser:
|
|
14517
|
+
promptUser: ask2
|
|
14368
14518
|
});
|
|
14369
14519
|
if (rc !== null) {
|
|
14370
14520
|
return rc;
|
|
@@ -14375,7 +14525,7 @@ async function platformAgent(opts) {
|
|
|
14375
14525
|
const confirm = opts.confirmPackaging ?? ((r, p) => confirmPackagingDefault(r, p, {
|
|
14376
14526
|
acceptRisk: opts.acceptRisk ?? false,
|
|
14377
14527
|
isTty,
|
|
14378
|
-
promptUser:
|
|
14528
|
+
promptUser: ask2
|
|
14379
14529
|
}));
|
|
14380
14530
|
const rc = await confirm(root, packaging);
|
|
14381
14531
|
if (rc !== null && rc !== 0) {
|
|
@@ -16861,12 +17011,13 @@ import { pieverseKeyHash as pieverseKeyHash4 } from "@bnbagent/studio-runtime/ll
|
|
|
16861
17011
|
import {
|
|
16862
17012
|
BSC_MAINNET_MIN_BNB,
|
|
16863
17013
|
BSC_MAINNET_MIN_U,
|
|
16864
|
-
BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS3,
|
|
16865
17014
|
BSC_TESTNET_MIN_BNB,
|
|
16866
17015
|
BSC_TESTNET_MIN_U,
|
|
17016
|
+
BSC_TESTNET_U_FAUCET_URL as BSC_TESTNET_U_FAUCET_URL3,
|
|
16867
17017
|
ERC8183_SUBMIT_GAS_RESERVE_BNB,
|
|
16868
17018
|
fromRaw as fromRaw3,
|
|
16869
|
-
getNetwork as getNetwork9
|
|
17019
|
+
getNetwork as getNetwork9,
|
|
17020
|
+
tbnbFaucetHint as tbnbFaucetHint3
|
|
16870
17021
|
} from "@bnbagent/studio-runtime/networks";
|
|
16871
17022
|
import { listModels as listModels2 } from "@bnbagent/studio-runtime/pieverse";
|
|
16872
17023
|
import * as walletRt5 from "@bnbagent/studio-runtime/wallet";
|
|
@@ -16971,6 +17122,9 @@ async function cmdDoctor(opts) {
|
|
|
16971
17122
|
checks.push(...await check8004(projectRoot, data, opts.network));
|
|
16972
17123
|
const destination = String(tableOf14(data, "deploy").destination ?? "self").trim().toLowerCase();
|
|
16973
17124
|
checks.push(...await checkDeployTools(data, destination));
|
|
17125
|
+
checks.push(
|
|
17126
|
+
...await checkPlatformZipBundle(data, destination, projectRoot)
|
|
17127
|
+
);
|
|
16974
17128
|
checks.push(...checkAgentsMdSkillTrigger(projectRoot));
|
|
16975
17129
|
printChecks(checks);
|
|
16976
17130
|
return checks.some((c2) => c2.status === FAIL) ? 1 : 0;
|
|
@@ -17053,16 +17207,12 @@ function checkAppMain(projectRootArg2) {
|
|
|
17053
17207
|
}
|
|
17054
17208
|
}
|
|
17055
17209
|
const stack = tableOf14(config, "stack");
|
|
17210
|
+
const faces = stackFaces(stack, tableOf14(config, "payments"));
|
|
17211
|
+
const stem2 = entryStemOf(faces);
|
|
17056
17212
|
const runtime = String(stack.runtime ?? "").toLowerCase();
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
} else if (runtime === "agentcore") {
|
|
17061
|
-
const faces = stackFaces(stack, tableOf14(config, "payments"));
|
|
17062
|
-
entrypoint = `src/${entryStemOf(faces)}.ts`;
|
|
17063
|
-
} else {
|
|
17064
|
-
entrypoint = "src/main.ts";
|
|
17065
|
-
}
|
|
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];
|
|
17066
17216
|
const entryFile = path39.join(agentDir, entrypoint);
|
|
17067
17217
|
if (!isFile17(entryFile)) {
|
|
17068
17218
|
return [
|
|
@@ -17073,7 +17223,7 @@ function checkAppMain(projectRootArg2) {
|
|
|
17073
17223
|
}
|
|
17074
17224
|
];
|
|
17075
17225
|
}
|
|
17076
|
-
const detail =
|
|
17226
|
+
const detail = entrypoint === "src/foundryMain.ts" ? `${entrypoint} (deploy entrypoint; \`bag dev\` serves src/main.ts or src/mcpMain.ts locally)` : entrypoint;
|
|
17077
17227
|
return [{ name: "agent entrypoint", status: PASS, detail }];
|
|
17078
17228
|
}
|
|
17079
17229
|
function checkAgentcoreName(projectRoot) {
|
|
@@ -17851,7 +18001,8 @@ async function checkBalances(projectRoot, data, networkOverride) {
|
|
|
17851
18001
|
const isMainnet = name === "bsc-mainnet";
|
|
17852
18002
|
const minBnb = isTestnet ? BSC_TESTNET_MIN_BNB : isMainnet ? BSC_MAINNET_MIN_BNB : 0;
|
|
17853
18003
|
const minBnbWei = BigInt(Math.round(minBnb * 1e6)) * 10n ** 12n;
|
|
17854
|
-
const
|
|
18004
|
+
const bnbFaucetHint = isTestnet ? ` \u2014 ${tbnbFaucetHint3(address)}` : "";
|
|
18005
|
+
const uFaucetHint = isTestnet ? ` \u2014 $U faucet: ${BSC_TESTNET_U_FAUCET_URL3}` : "";
|
|
17855
18006
|
const bnbRaw = await readNativeBalanceRaw(address, name);
|
|
17856
18007
|
const reserve = ERC8183_SUBMIT_GAS_RESERVE_BNB;
|
|
17857
18008
|
const reserveHint = ` (each on-chain action reserves \u2248 ${reserve} BNB worst-case)`;
|
|
@@ -17872,7 +18023,7 @@ async function checkBalances(projectRoot, data, networkOverride) {
|
|
|
17872
18023
|
out.push({
|
|
17873
18024
|
name: "wallet BNB balance",
|
|
17874
18025
|
status: WARN,
|
|
17875
|
-
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}`
|
|
17876
18027
|
});
|
|
17877
18028
|
}
|
|
17878
18029
|
const uToken = net2.tokens.U;
|
|
@@ -17898,7 +18049,7 @@ async function checkBalances(projectRoot, data, networkOverride) {
|
|
|
17898
18049
|
out.push({
|
|
17899
18050
|
name: "wallet U balance",
|
|
17900
18051
|
status: WARN,
|
|
17901
|
-
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}`
|
|
17902
18053
|
});
|
|
17903
18054
|
}
|
|
17904
18055
|
return out;
|
|
@@ -18047,11 +18198,7 @@ async function checkDeployTools(data, destination) {
|
|
|
18047
18198
|
});
|
|
18048
18199
|
if (destination === "platform") {
|
|
18049
18200
|
const out = [
|
|
18050
|
-
|
|
18051
|
-
name: "deploy: bnbagent-deploy",
|
|
18052
|
-
status: INFO,
|
|
18053
|
-
detail: "[deploy].destination='platform' also delegates to bnbagent-deploy (bunx); `bag deploy prepare` verifies it."
|
|
18054
|
-
},
|
|
18201
|
+
emit2(await checkBunx()),
|
|
18055
18202
|
{
|
|
18056
18203
|
name: "deploy: AWS credentials",
|
|
18057
18204
|
status: INFO,
|
|
@@ -18081,6 +18228,49 @@ async function checkDeployTools(data, destination) {
|
|
|
18081
18228
|
}
|
|
18082
18229
|
return (await deployChecks()).map(emit2);
|
|
18083
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
|
+
}
|
|
18084
18274
|
function checkAgentsMdSkillTrigger(projectRoot) {
|
|
18085
18275
|
const ws = findStudioWorkspaceRoot4(projectRoot);
|
|
18086
18276
|
if (ws === null) {
|
|
@@ -18259,9 +18449,9 @@ import {
|
|
|
18259
18449
|
updateServiceEndpoint as updateServiceEndpoint2
|
|
18260
18450
|
} from "@bnbagent/studio-runtime/erc8004";
|
|
18261
18451
|
import {
|
|
18262
|
-
BSC_TESTNET_FAUCET_URLS as BSC_TESTNET_FAUCET_URLS4,
|
|
18263
18452
|
fromRaw as fromRaw4,
|
|
18264
|
-
getNetwork as getNetwork10
|
|
18453
|
+
getNetwork as getNetwork10,
|
|
18454
|
+
tbnbFaucetHint as tbnbFaucetHint4
|
|
18265
18455
|
} from "@bnbagent/studio-runtime/networks";
|
|
18266
18456
|
import * as walletRt6 from "@bnbagent/studio-runtime/wallet";
|
|
18267
18457
|
import { Option as Option5 } from "commander";
|
|
@@ -18423,8 +18613,7 @@ async function precheckRegisterGas(wallet, network) {
|
|
|
18423
18613
|
if (balance >= REGISTER_MIN_BNB) {
|
|
18424
18614
|
return null;
|
|
18425
18615
|
}
|
|
18426
|
-
|
|
18427
|
-
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)}`;
|
|
18428
18617
|
}
|
|
18429
18618
|
function syncAgentRegistry(agentId, op) {
|
|
18430
18619
|
try {
|
|
@@ -19374,7 +19563,7 @@ async function promptInstallScope() {
|
|
|
19374
19563
|
}
|
|
19375
19564
|
function printNextSteps2() {
|
|
19376
19565
|
printOut(
|
|
19377
|
-
"\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."
|
|
19378
19567
|
);
|
|
19379
19568
|
}
|
|
19380
19569
|
async function installInteractive(flags) {
|
|
@@ -21183,6 +21372,10 @@ async function main(argv) {
|
|
|
21183
21372
|
if (err instanceof CliExit) {
|
|
21184
21373
|
return err.code;
|
|
21185
21374
|
}
|
|
21375
|
+
if (err instanceof Error && err.name === "PromptCancelled") {
|
|
21376
|
+
process.stderr.write("cancelled.\n");
|
|
21377
|
+
return 130;
|
|
21378
|
+
}
|
|
21186
21379
|
if (isCommanderExit(err)) {
|
|
21187
21380
|
return err.exitCode;
|
|
21188
21381
|
}
|