@bnbagent/studio-cli 0.0.11-alpha.4 → 0.0.11-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bag.js +196 -25
- package/dist/{chunk-GKFTJDDJ.js → chunk-VVHPUKLV.js} +48 -11
- package/dist/{deployCli-YYV7FFFG.js → deployCli-5DZVAKMZ.js} +1 -1
- package/package.json +2 -2
- package/skills/bnbagent-studio.md +4 -4
- package/skills/references/bnbagent-studio-adding-to-project.md +1 -1
- package/skills/references/bnbagent-studio-scaffolding-agent.md +4 -4
- package/skills/references/bnbagent-studio-selling-via-8183.md +1 -1
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +1 -1
- package/skills/references/bnbagent-studio-use-azure-foundry.md +8 -7
- package/skills/references/bnbagent-studio-use-bnb-trial.md +1 -1
package/dist/bag.js
CHANGED
|
@@ -47,10 +47,12 @@ import {
|
|
|
47
47
|
whichBin,
|
|
48
48
|
withDeployFiles,
|
|
49
49
|
x402DeploySummary,
|
|
50
|
+
x402DeploySummaryFromSnapshot,
|
|
51
|
+
x402DeploymentSnapshot,
|
|
50
52
|
x402SellerIsFree,
|
|
51
53
|
x402SellerPricingState,
|
|
52
54
|
x402SellerUsesB402
|
|
53
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-VVHPUKLV.js";
|
|
54
56
|
import {
|
|
55
57
|
TWAK_CLI_MIN_VERSION,
|
|
56
58
|
TWAK_CLI_VERSION,
|
|
@@ -228,7 +230,7 @@ import {
|
|
|
228
230
|
var CAMPAIGN_DOC_URL = "https://www.bnbchain.org/en/blog/bnb-agent-studio-is-live-on-bnb-chain-ai-agents-from-one-prompt";
|
|
229
231
|
var CAMPAIGN_CHECK_TIMEOUT_MS = 6e3;
|
|
230
232
|
async function fetchCampaignActive() {
|
|
231
|
-
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-
|
|
233
|
+
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-5DZVAKMZ.js");
|
|
232
234
|
const controller = new AbortController();
|
|
233
235
|
const timer = setTimeout(() => controller.abort(), CAMPAIGN_CHECK_TIMEOUT_MS);
|
|
234
236
|
try {
|
|
@@ -3363,6 +3365,25 @@ function protocolFaces(value) {
|
|
|
3363
3365
|
return null;
|
|
3364
3366
|
}
|
|
3365
3367
|
}
|
|
3368
|
+
function recordedX402Snapshot(azure) {
|
|
3369
|
+
const status = text(azure.deployed_x402_status);
|
|
3370
|
+
const priceMode = text(azure.deployed_x402_price_mode);
|
|
3371
|
+
const credentialsComplete = azure.deployed_x402_credentials_complete;
|
|
3372
|
+
if (!["active", "free", "dormant"].includes(status ?? "") || !["paid", "free", "invalid"].includes(priceMode ?? "") || typeof credentialsComplete !== "boolean") {
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
const expectedStatus = priceMode === "free" ? "free" : priceMode === "paid" && credentialsComplete ? "active" : "dormant";
|
|
3376
|
+
if (status !== expectedStatus) return null;
|
|
3377
|
+
return {
|
|
3378
|
+
status,
|
|
3379
|
+
priceMode,
|
|
3380
|
+
credentialsComplete
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
function recordedX402Carrier(azure) {
|
|
3384
|
+
const carrier = text(azure.deployed_x402_carrier);
|
|
3385
|
+
return carrier === "http-envelope-v1" || carrier === "incompatible-scaffold" ? carrier : void 0;
|
|
3386
|
+
}
|
|
3366
3387
|
function descriptorName(workspaceRoot) {
|
|
3367
3388
|
try {
|
|
3368
3389
|
const data = JSON.parse(
|
|
@@ -3420,6 +3441,8 @@ function discoverRecordedDeployments(root) {
|
|
|
3420
3441
|
const azureEndpoint = text(azure.agent_endpoint);
|
|
3421
3442
|
const azureDeploymentId = text(azure.deployment_id);
|
|
3422
3443
|
const azureFaces = protocolFaces(azure.deployed_faces);
|
|
3444
|
+
const azureX402 = recordedX402Snapshot(azure);
|
|
3445
|
+
const azureX402Carrier = recordedX402Carrier(azure);
|
|
3423
3446
|
if (azureEndpoint || azureDeploymentId || text(azure.last_deploy_at)) {
|
|
3424
3447
|
found.push({
|
|
3425
3448
|
provider: "azure",
|
|
@@ -3428,6 +3451,8 @@ function discoverRecordedDeployments(root) {
|
|
|
3428
3451
|
deploymentId: azureDeploymentId,
|
|
3429
3452
|
endpoint: azureEndpoint,
|
|
3430
3453
|
...azureFaces ? { faces: azureFaces } : {},
|
|
3454
|
+
...azureX402 ? { x402: azureX402 } : {},
|
|
3455
|
+
...azureX402Carrier ? { x402Carrier: azureX402Carrier } : {},
|
|
3431
3456
|
status: "active"
|
|
3432
3457
|
});
|
|
3433
3458
|
}
|
|
@@ -4148,6 +4173,52 @@ function isFile6(p) {
|
|
|
4148
4173
|
return false;
|
|
4149
4174
|
}
|
|
4150
4175
|
}
|
|
4176
|
+
function inspectAzureX402Carrier(agentRoot2) {
|
|
4177
|
+
const dockerfile = path16.join(agentRoot2, "Dockerfile");
|
|
4178
|
+
let entryStem = null;
|
|
4179
|
+
if (isFile6(dockerfile)) {
|
|
4180
|
+
const docker = fs17.readFileSync(dockerfile, "utf8");
|
|
4181
|
+
const match = docker.match(
|
|
4182
|
+
/(?:CMD|ENTRYPOINT)\s*\[\s*["']node["']\s*,\s*["'](?:\.\/)?dist\/([^"'/]+)\.js["']\s*\]/m
|
|
4183
|
+
);
|
|
4184
|
+
entryStem = match?.[1] ?? null;
|
|
4185
|
+
}
|
|
4186
|
+
if (entryStem === null) {
|
|
4187
|
+
return {
|
|
4188
|
+
status: "incompatible-scaffold",
|
|
4189
|
+
entrypoint: null,
|
|
4190
|
+
detail: "Dockerfile does not identify the built Azure entrypoint as CMD/ENTRYPOINT node dist/<name>.js"
|
|
4191
|
+
};
|
|
4192
|
+
}
|
|
4193
|
+
const entrypoint = `src/${entryStem}.ts`;
|
|
4194
|
+
const entryFile = path16.join(agentRoot2, entrypoint);
|
|
4195
|
+
if (!isFile6(entryFile)) {
|
|
4196
|
+
return {
|
|
4197
|
+
status: "incompatible-scaffold",
|
|
4198
|
+
entrypoint,
|
|
4199
|
+
detail: `${entrypoint} is selected by Dockerfile but its source is missing`
|
|
4200
|
+
};
|
|
4201
|
+
}
|
|
4202
|
+
const source = fs17.readFileSync(entryFile, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
4203
|
+
const hasSeller = /\bX402Seller\s*\.\s*create\s*\(/m.test(source);
|
|
4204
|
+
const hasCarrier = /\bcreateEnvelopeMiddleware\s*\(/m.test(source);
|
|
4205
|
+
if (!hasSeller || !hasCarrier) {
|
|
4206
|
+
const missing = [
|
|
4207
|
+
...hasCarrier ? [] : ["createEnvelopeMiddleware"],
|
|
4208
|
+
...hasSeller ? [] : ["X402Seller.create"]
|
|
4209
|
+
];
|
|
4210
|
+
return {
|
|
4211
|
+
status: "incompatible-scaffold",
|
|
4212
|
+
entrypoint,
|
|
4213
|
+
detail: `${entrypoint} does not mount ${missing.join(" and ")}`
|
|
4214
|
+
};
|
|
4215
|
+
}
|
|
4216
|
+
return {
|
|
4217
|
+
status: "http-envelope-v1",
|
|
4218
|
+
entrypoint,
|
|
4219
|
+
detail: `${entrypoint} mounts the X402 seller and envelope carrier`
|
|
4220
|
+
};
|
|
4221
|
+
}
|
|
4151
4222
|
function tableOf4(cfg, key) {
|
|
4152
4223
|
const v = cfg[key];
|
|
4153
4224
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
@@ -4175,9 +4246,15 @@ function recordAzureDeployment(root, data, endpoint) {
|
|
|
4175
4246
|
if (agentRoot2 === null) return;
|
|
4176
4247
|
const tomlPath = path16.join(agentRoot2, "studio.toml");
|
|
4177
4248
|
let deployedFaces = null;
|
|
4249
|
+
let deployedX402 = null;
|
|
4250
|
+
let deployedX402Carrier = null;
|
|
4178
4251
|
try {
|
|
4179
4252
|
const cfg = loadStudioCfg(deployWorkspaceRoot(root));
|
|
4180
4253
|
deployedFaces = stackFaces(tableOf4(cfg, "stack"), tableOf4(cfg, "payments"));
|
|
4254
|
+
if (hasX402Face(deployedFaces)) {
|
|
4255
|
+
deployedX402 = x402DeploymentSnapshot(agentRoot2, "self");
|
|
4256
|
+
deployedX402Carrier = inspectAzureX402Carrier(agentRoot2).status;
|
|
4257
|
+
}
|
|
4181
4258
|
} catch {
|
|
4182
4259
|
}
|
|
4183
4260
|
try {
|
|
@@ -4192,6 +4269,30 @@ function recordAzureDeployment(root, data, endpoint) {
|
|
|
4192
4269
|
}
|
|
4193
4270
|
if (deployedFaces) {
|
|
4194
4271
|
patchTomlKv(tomlPath, "azure", "deployed_faces", deployedFaces);
|
|
4272
|
+
patchTomlKv(
|
|
4273
|
+
tomlPath,
|
|
4274
|
+
"azure",
|
|
4275
|
+
"deployed_x402_status",
|
|
4276
|
+
deployedX402?.status ?? ""
|
|
4277
|
+
);
|
|
4278
|
+
patchTomlKv(
|
|
4279
|
+
tomlPath,
|
|
4280
|
+
"azure",
|
|
4281
|
+
"deployed_x402_price_mode",
|
|
4282
|
+
deployedX402?.priceMode ?? ""
|
|
4283
|
+
);
|
|
4284
|
+
patchTomlKv(
|
|
4285
|
+
tomlPath,
|
|
4286
|
+
"azure",
|
|
4287
|
+
"deployed_x402_credentials_complete",
|
|
4288
|
+
deployedX402?.credentialsComplete ?? false
|
|
4289
|
+
);
|
|
4290
|
+
patchTomlKv(
|
|
4291
|
+
tomlPath,
|
|
4292
|
+
"azure",
|
|
4293
|
+
"deployed_x402_carrier",
|
|
4294
|
+
deployedX402Carrier ?? ""
|
|
4295
|
+
);
|
|
4195
4296
|
}
|
|
4196
4297
|
patchTomlKv(tomlPath, "azure", "last_deploy_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
4197
4298
|
} catch {
|
|
@@ -4211,6 +4312,10 @@ function clearAzureEndpoint(root) {
|
|
|
4211
4312
|
patchTomlKv(tomlPath, "azure", key, "");
|
|
4212
4313
|
}
|
|
4213
4314
|
patchTomlKv(tomlPath, "azure", "deployed_faces", []);
|
|
4315
|
+
patchTomlKv(tomlPath, "azure", "deployed_x402_status", "");
|
|
4316
|
+
patchTomlKv(tomlPath, "azure", "deployed_x402_price_mode", "");
|
|
4317
|
+
patchTomlKv(tomlPath, "azure", "deployed_x402_credentials_complete", false);
|
|
4318
|
+
patchTomlKv(tomlPath, "azure", "deployed_x402_carrier", "");
|
|
4214
4319
|
} catch {
|
|
4215
4320
|
}
|
|
4216
4321
|
}
|
|
@@ -4507,6 +4612,20 @@ var checkEntrypointAndDockerfile = async (root, _target) => {
|
|
|
4507
4612
|
details: { entrypoint: entry }
|
|
4508
4613
|
});
|
|
4509
4614
|
}
|
|
4615
|
+
if (hasX402Face(faces)) {
|
|
4616
|
+
const carrier = inspectAzureX402Carrier(agentRoot2);
|
|
4617
|
+
if (carrier.status !== "http-envelope-v1") {
|
|
4618
|
+
findings.push({
|
|
4619
|
+
level: "CRITICAL",
|
|
4620
|
+
name: "azure_x402_entrypoint_compatible",
|
|
4621
|
+
message: `${carrier.detail}. This scaffold cannot serve X402 even though studio.toml enables it. In a clean parent directory, run \`bag init azurex402migration --runtime azure-foundry --protocols ${faces.join(",")} --no-install --no-onboard\`, then review and merge its src/unifiedMain.ts, Dockerfile, and package scripts before redeploying. Studio will not overwrite user-owned agent code.`,
|
|
4622
|
+
details: {
|
|
4623
|
+
entrypoint: carrier.entrypoint,
|
|
4624
|
+
carrier: carrier.status
|
|
4625
|
+
}
|
|
4626
|
+
});
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4510
4629
|
if (!isFile6(path16.join(agentRoot2, "Dockerfile"))) {
|
|
4511
4630
|
findings.push({
|
|
4512
4631
|
level: "CRITICAL",
|
|
@@ -7901,7 +8020,7 @@ function registerInit(program) {
|
|
|
7901
8020
|
).addOption(
|
|
7902
8021
|
new Option2(
|
|
7903
8022
|
"--protocols <faces>",
|
|
7904
|
-
"Comma-separated public faces to expose; recorded in studio.toml [stack].protocols. Any non-empty combination of A2A, MCP, X402 (case-insensitive; default: A2A)."
|
|
8023
|
+
"Comma-separated public faces to expose; recorded in studio.toml [stack].protocols. Any non-empty combination of A2A, MCP, X402 (case-insensitive; default: A2A,X402)."
|
|
7905
8024
|
)
|
|
7906
8025
|
).addOption(
|
|
7907
8026
|
new Option2(
|
|
@@ -7911,7 +8030,7 @@ function registerInit(program) {
|
|
|
7911
8030
|
).addOption(
|
|
7912
8031
|
new Option2(
|
|
7913
8032
|
"--rails <rails>",
|
|
7914
|
-
"Commerce rail(s) to scaffold: 8183
|
|
8033
|
+
"Commerce rail(s) to scaffold: 8183, b402, or both (default; Altana defaults to 8183)."
|
|
7915
8034
|
).choices(["8183", "b402", "both"])
|
|
7916
8035
|
).option(
|
|
7917
8036
|
"--erc8183-price <base-units>",
|
|
@@ -8063,9 +8182,12 @@ async function cmdInitFlow(nameArg, opts) {
|
|
|
8063
8182
|
printErr("error: pass either --protocols or --protocol, not both.");
|
|
8064
8183
|
return 2;
|
|
8065
8184
|
}
|
|
8185
|
+
const facesExplicit = opts.protocols !== void 0 || opts.protocol !== void 0;
|
|
8066
8186
|
let faces;
|
|
8067
8187
|
try {
|
|
8068
|
-
faces = normalizeProtocolFaces(
|
|
8188
|
+
faces = normalizeProtocolFaces(
|
|
8189
|
+
opts.protocols ?? opts.protocol ?? "A2A,X402"
|
|
8190
|
+
);
|
|
8069
8191
|
if (opts.protocol !== void 0 && faces.length !== 1) {
|
|
8070
8192
|
throw new Error("--protocol is a single-face alias; use --protocols");
|
|
8071
8193
|
}
|
|
@@ -8101,7 +8223,13 @@ async function cmdInitFlow(nameArg, opts) {
|
|
|
8101
8223
|
if (llmProvider === null) {
|
|
8102
8224
|
return 2;
|
|
8103
8225
|
}
|
|
8104
|
-
|
|
8226
|
+
const inferredRails = opts.rails ?? (facesExplicit ? hasX402Face(faces) ? "both" : "8183" : walletKind2 === "altana" ? "8183" : void 0);
|
|
8227
|
+
let rails = await resolveRails(inferredRails, isTty);
|
|
8228
|
+
if (!facesExplicit) {
|
|
8229
|
+
faces = normalizeProtocolFaces(
|
|
8230
|
+
rails === "8183" ? ["A2A"] : ["A2A", "X402"]
|
|
8231
|
+
);
|
|
8232
|
+
}
|
|
8105
8233
|
if (hasX402Face(faces) && rails === "8183") {
|
|
8106
8234
|
rails = "both";
|
|
8107
8235
|
} else if (hasX402Face(faces) && rails !== "both") {
|
|
@@ -8855,6 +8983,9 @@ function renderAzureSection(name, account, project) {
|
|
|
8855
8983
|
[azure]
|
|
8856
8984
|
# Hosted-Agents-supported region (eastus does NOT support Hosted Agents).
|
|
8857
8985
|
location = "${DEFAULT_LOCATION}"
|
|
8986
|
+
# Optional Azure subscription id. Set it when the signed-in identity can access
|
|
8987
|
+
# more than one subscription so non-interactive deploy never guesses.
|
|
8988
|
+
subscription_id = ""
|
|
8858
8989
|
# account_name MUST equal subdomain \u2014 the runtime derives the storage host
|
|
8859
8990
|
# (https://{account_name}.services.ai.azure.com) from it; a mismatch is NXDOMAIN.
|
|
8860
8991
|
account_name = "${azureName}"
|
|
@@ -9261,13 +9392,15 @@ async function resolveRails(flagValue, isTty) {
|
|
|
9261
9392
|
if (flagValue === "8183" || flagValue === "b402" || flagValue === "both") {
|
|
9262
9393
|
return flagValue;
|
|
9263
9394
|
}
|
|
9264
|
-
if (!isTty) return "
|
|
9265
|
-
const answer = (await promptUser("Commerce rails [8183/b402/both, Enter =
|
|
9266
|
-
if (answer === "b402" || answer === "both")
|
|
9267
|
-
|
|
9268
|
-
printErr(`hint: unknown commerce rail '${answer}' \u2014 using 8183.`);
|
|
9395
|
+
if (!isTty) return "both";
|
|
9396
|
+
const answer = (await promptUser("Commerce rails [8183/b402/both, Enter = both]: ")).trim().toLowerCase();
|
|
9397
|
+
if (answer === "8183" || answer === "b402" || answer === "both") {
|
|
9398
|
+
return answer;
|
|
9269
9399
|
}
|
|
9270
|
-
|
|
9400
|
+
if (answer !== "") {
|
|
9401
|
+
printErr(`hint: unknown commerce rail '${answer}' \u2014 using both.`);
|
|
9402
|
+
}
|
|
9403
|
+
return "both";
|
|
9271
9404
|
}
|
|
9272
9405
|
var DEFAULT_ERC8183_PRICE = "100000000000000000";
|
|
9273
9406
|
async function resolveErc8183Price(flagValue, isTty) {
|
|
@@ -16760,6 +16893,12 @@ function azureX402CarrierBody() {
|
|
|
16760
16893
|
function sameFaces(a, b) {
|
|
16761
16894
|
return a.length === b.length && a.every((face, index) => face === b[index]);
|
|
16762
16895
|
}
|
|
16896
|
+
function sameX402Snapshot(a, b) {
|
|
16897
|
+
if (a === null || a === void 0 || b === null || b === void 0) {
|
|
16898
|
+
return a === b;
|
|
16899
|
+
}
|
|
16900
|
+
return a.status === b.status && a.priceMode === b.priceMode && a.credentialsComplete === b.credentialsComplete;
|
|
16901
|
+
}
|
|
16763
16902
|
function printAzureInfo(root, deployment, opts) {
|
|
16764
16903
|
const endpoint = deployment.endpoint;
|
|
16765
16904
|
if (!endpoint) {
|
|
@@ -16788,20 +16927,34 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16788
16927
|
const currentFaces = agentFacesOf(agentRoot2);
|
|
16789
16928
|
const faces = deployment.faces ?? currentFaces;
|
|
16790
16929
|
const facesSource = deployment.faces ? "deployment-record" : "current-scaffold";
|
|
16791
|
-
const
|
|
16930
|
+
const facesDrift = deployment.faces !== void 0 && !sameFaces(deployment.faces, currentFaces);
|
|
16792
16931
|
const hasX402 = hasX402Face(faces);
|
|
16793
16932
|
const hasA2a = hasA2aFace(faces);
|
|
16794
|
-
const
|
|
16795
|
-
const
|
|
16796
|
-
const
|
|
16797
|
-
const
|
|
16798
|
-
const
|
|
16933
|
+
const currentX402 = hasX402Face(currentFaces) ? x402DeploymentSnapshot(agentRoot2, "self") : null;
|
|
16934
|
+
const x402State = deployment.x402 ?? currentX402;
|
|
16935
|
+
const x402StateSource = deployment.x402 ? "deployment-record" : "current-scaffold";
|
|
16936
|
+
const x402Drift = deployment.x402 !== void 0 && !sameX402Snapshot(deployment.x402, currentX402);
|
|
16937
|
+
const currentCarrier = hasX402Face(currentFaces) ? inspectAzureX402Carrier(agentRoot2).status : null;
|
|
16938
|
+
const carrierDrift = deployment.x402Carrier !== void 0 && deployment.x402Carrier !== currentCarrier;
|
|
16939
|
+
const configurationDrift = facesDrift || x402Drift || carrierDrift;
|
|
16940
|
+
const carrierVerified = deployment.x402Carrier === "http-envelope-v1";
|
|
16941
|
+
const x402Summary = hasX402 ? carrierVerified ? deployment.x402 ? x402DeploySummaryFromSnapshot(
|
|
16942
|
+
deployment.x402,
|
|
16943
|
+
"azure-foundry",
|
|
16944
|
+
"self",
|
|
16945
|
+
null
|
|
16946
|
+
) : x402DeploySummary(agentRoot2, "self", null) : deployment.x402Carrier === "incompatible-scaffold" ? "The deployed Azure entrypoint did not mount createEnvelopeMiddleware and X402Seller. Re-scaffold the unified entrypoint, review the diff, and redeploy." : "This deployment record predates X402 carrier verification, so the deployed artifact cannot be treated as X402-capable. Verify or migrate the unified entrypoint and redeploy." : "";
|
|
16947
|
+
const x402Status = carrierVerified ? x402State?.status ?? (x402Summary.includes("ACTIVE in FREE mode") ? "free" : x402Summary.startsWith("x402 rail is ACTIVE") ? "active" : "dormant") : "incompatible-scaffold";
|
|
16948
|
+
const x402Body = hasX402 && carrierVerified ? azureX402CarrierBody() : void 0;
|
|
16949
|
+
const body = hasA2a ? azureNegotiateQuickVerifyBody() : x402Body;
|
|
16950
|
+
const x402Info = hasX402 ? carrierVerified ? {
|
|
16799
16951
|
status: x402Status,
|
|
16800
16952
|
access: x402Status === "dormant" ? "dormant" : "requires-external-gateway",
|
|
16801
16953
|
public_url: null,
|
|
16802
16954
|
carrier: "http-envelope-v1",
|
|
16803
16955
|
gateway_guide: foundryX402GatewayGuideUrl(),
|
|
16804
16956
|
summary: x402Summary || "x402 seller state is not available locally.",
|
|
16957
|
+
state_source: x402StateSource,
|
|
16805
16958
|
...x402Status === "dormant" ? {} : {
|
|
16806
16959
|
request: {
|
|
16807
16960
|
method: "POST",
|
|
@@ -16810,6 +16963,12 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16810
16963
|
executes_seller_work: false
|
|
16811
16964
|
}
|
|
16812
16965
|
}
|
|
16966
|
+
} : {
|
|
16967
|
+
status: "incompatible-scaffold",
|
|
16968
|
+
access: "incompatible-scaffold",
|
|
16969
|
+
public_url: null,
|
|
16970
|
+
summary: x402Summary,
|
|
16971
|
+
state_source: deployment.x402Carrier ? "deployment-record" : "unverified-deployment"
|
|
16813
16972
|
} : void 0;
|
|
16814
16973
|
if (opts.json) {
|
|
16815
16974
|
printOut(
|
|
@@ -16828,11 +16987,11 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16828
16987
|
resource: AZURE_FOUNDRY_TOKEN_RESOURCE,
|
|
16829
16988
|
scope: AZURE_FOUNDRY_TOKEN_SCOPE
|
|
16830
16989
|
},
|
|
16831
|
-
request: {
|
|
16990
|
+
request: body ? {
|
|
16832
16991
|
method: "POST",
|
|
16833
16992
|
content_type: "application/json",
|
|
16834
16993
|
body
|
|
16835
|
-
},
|
|
16994
|
+
} : null,
|
|
16836
16995
|
...x402Info ? { x402: x402Info } : {}
|
|
16837
16996
|
},
|
|
16838
16997
|
null,
|
|
@@ -16846,16 +17005,24 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16846
17005
|
printOut(` deployed faces: ${faces.join(", ")} (${facesSource})`);
|
|
16847
17006
|
if (configurationDrift) {
|
|
16848
17007
|
printErr(
|
|
16849
|
-
|
|
17008
|
+
"warning: current scaffold/payment configuration differs from the recorded deployment; redeploy before treating local config as live."
|
|
16850
17009
|
);
|
|
16851
17010
|
}
|
|
16852
17011
|
printOut(
|
|
16853
17012
|
` authentication: Microsoft Entra bearer token (resource ${AZURE_FOUNDRY_TOKEN_RESOURCE}; SDK scope ${AZURE_FOUNDRY_TOKEN_SCOPE})`
|
|
16854
17013
|
);
|
|
16855
|
-
|
|
16856
|
-
|
|
17014
|
+
if (body) {
|
|
17015
|
+
printOut(" request: POST application/json");
|
|
17016
|
+
printOut(` body: ${JSON.stringify(body)}`);
|
|
17017
|
+
} else {
|
|
17018
|
+
printOut(
|
|
17019
|
+
" request: unavailable until the X402 scaffold is migrated and redeployed"
|
|
17020
|
+
);
|
|
17021
|
+
}
|
|
16857
17022
|
if (x402Info) {
|
|
16858
|
-
if (x402Info.access === "
|
|
17023
|
+
if (x402Info.access === "incompatible-scaffold") {
|
|
17024
|
+
printOut(` x402 access: incompatible-scaffold \u2014 ${x402Info.summary}`);
|
|
17025
|
+
} else if (x402Info.access === "dormant") {
|
|
16859
17026
|
printOut(` x402 access: dormant \u2014 ${x402Info.summary}`);
|
|
16860
17027
|
} else {
|
|
16861
17028
|
printOut(
|
|
@@ -16872,7 +17039,7 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16872
17039
|
printOut(` x402 gateway guide: ${foundryX402GatewayGuideUrl()}`);
|
|
16873
17040
|
}
|
|
16874
17041
|
}
|
|
16875
|
-
if (opts.withCurl) {
|
|
17042
|
+
if (opts.withCurl && body) {
|
|
16876
17043
|
printOut(
|
|
16877
17044
|
hasA2a ? "\nQuick-verify curl:" : "\nX402 no-work route-probe curl:"
|
|
16878
17045
|
);
|
|
@@ -16889,6 +17056,10 @@ function printAzureInfo(root, deployment, opts) {
|
|
|
16889
17056
|
printOut(
|
|
16890
17057
|
"\n The Azure CLI command is only a convenient way to mint a token for this curl. Deployment itself does not require az/azd; DefaultAzureCredential or ClientSecretCredential can mint the same scope in an application."
|
|
16891
17058
|
);
|
|
17059
|
+
} else if (opts.withCurl) {
|
|
17060
|
+
printErr(
|
|
17061
|
+
"warning: no X402 curl was emitted because the recorded Azure deployment does not prove http-envelope-v1 support; migrate and redeploy first."
|
|
17062
|
+
);
|
|
16892
17063
|
}
|
|
16893
17064
|
return 0;
|
|
16894
17065
|
}
|
|
@@ -686,8 +686,8 @@ function packageRoot() {
|
|
|
686
686
|
}
|
|
687
687
|
}
|
|
688
688
|
function studioCliVersion() {
|
|
689
|
-
if ("0.0.11-alpha.
|
|
690
|
-
return "0.0.11-alpha.
|
|
689
|
+
if ("0.0.11-alpha.6") {
|
|
690
|
+
return "0.0.11-alpha.6";
|
|
691
691
|
}
|
|
692
692
|
const file = path3.join(packageRoot(), "package.json");
|
|
693
693
|
const pkg = JSON.parse(fs3.readFileSync(file, "utf-8"));
|
|
@@ -831,14 +831,47 @@ function loadDeployConfig(root) {
|
|
|
831
831
|
return { agentRoot, cfg: {} };
|
|
832
832
|
}
|
|
833
833
|
}
|
|
834
|
-
function
|
|
834
|
+
function deploymentStatus(priceMode, credentialsComplete, runtime, destination) {
|
|
835
|
+
if (destination !== "platform" && !X402_CAPABLE_RUNTIMES.has(runtime)) {
|
|
836
|
+
return "dormant";
|
|
837
|
+
}
|
|
838
|
+
if (priceMode === "free") return "free";
|
|
839
|
+
if (priceMode === "paid" && credentialsComplete) return "active";
|
|
840
|
+
return "dormant";
|
|
841
|
+
}
|
|
842
|
+
function x402DeploymentSnapshot(root, destination) {
|
|
835
843
|
const { agentRoot, cfg } = loadDeployConfig(root);
|
|
836
|
-
if (!commerceRails(cfg).x402) return
|
|
844
|
+
if (!commerceRails(cfg).x402) return null;
|
|
837
845
|
const seller = table3(table3(cfg.payments).x402_seller);
|
|
838
846
|
const pricing = x402SellerPricingState(seller);
|
|
839
847
|
const credentials = b402Credentials(agentRoot);
|
|
840
|
-
const
|
|
848
|
+
const priceMode = pricing.kind;
|
|
841
849
|
const runtime = String(table3(cfg.stack).runtime ?? "agentcore");
|
|
850
|
+
return {
|
|
851
|
+
status: deploymentStatus(
|
|
852
|
+
priceMode,
|
|
853
|
+
credentials.complete,
|
|
854
|
+
runtime,
|
|
855
|
+
destination
|
|
856
|
+
),
|
|
857
|
+
priceMode,
|
|
858
|
+
credentialsComplete: credentials.complete
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
function x402DeploySummary(root, destination, publicUrl) {
|
|
862
|
+
const { cfg } = loadDeployConfig(root);
|
|
863
|
+
const snapshot = x402DeploymentSnapshot(root, destination);
|
|
864
|
+
if (snapshot === null) return "";
|
|
865
|
+
const runtime = String(table3(cfg.stack).runtime ?? "agentcore");
|
|
866
|
+
return x402DeploySummaryFromSnapshot(
|
|
867
|
+
snapshot,
|
|
868
|
+
runtime,
|
|
869
|
+
destination,
|
|
870
|
+
publicUrl
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
function x402DeploySummaryFromSnapshot(snapshot, runtime, destination, publicUrl) {
|
|
874
|
+
const activation = `${B402_PAID_ONBOARDING_GUIDANCE} Then run the bnbagent-studio-selling-via-b402 skill, fill the four B402_* variables in .studio/.env.local, and redeploy.`;
|
|
842
875
|
if (destination !== "platform" && !X402_CAPABLE_RUNTIMES.has(runtime)) {
|
|
843
876
|
return `x402 rail is FORCED DORMANT: the ${runtime} runtime has no x402 path. Deploy to AgentCore or Azure Foundry (managed platform or self-hosted) to activate the rail.`;
|
|
844
877
|
}
|
|
@@ -846,10 +879,10 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
846
879
|
const runtimeLabel = azure ? "Azure Foundry" : "AgentCore";
|
|
847
880
|
const tunnelLine = azure ? 'The front wraps each request as envelope-v1 JSON, {"v":1,"method":"POST","path":"/x402","headers":{...},"body":"<base64>"}, inside an Entra-authenticated Foundry invocation (POST \u2026/agents/<name>/endpoint/protocols/invocations with an https://ai.azure.com bearer). Limits: 1 MiB request, 5 MiB response, no streaming.' : 'The front wraps each request as envelope-v1 JSON, {"v":1,"method":"POST","path":"/x402","headers":{...},"body":"<base64>"}, inside an authenticated AgentCore invocation. The default Bag self-deploy uses Cognito OAuth over HTTPS; IAM runtimes may use SDK/SigV4. Limits: 1 MiB request, 5 MiB response, no streaming.';
|
|
848
881
|
const gatewayDocLine = azure ? `Gateway example: https://unpkg.com/@bnbagent/studio-cli@${studioCliVersion()}/skills/references/bnbagent-studio-use-azure-foundry.md#x402-external-gateway` : "Gateway example: https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/self-hosted-x402-gateway.md";
|
|
849
|
-
if (
|
|
882
|
+
if (snapshot.priceMode === "invalid") {
|
|
850
883
|
return "x402 rail is DORMANT: price_usd is invalid; run `bag doctor`.";
|
|
851
884
|
}
|
|
852
|
-
if (
|
|
885
|
+
if (snapshot.priceMode === "free") {
|
|
853
886
|
if (destination !== "platform") {
|
|
854
887
|
return [
|
|
855
888
|
`x402 rail is ACTIVE in FREE mode (self-hosted ${runtimeLabel}).`,
|
|
@@ -867,7 +900,7 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
867
900
|
"B402 verify/settle is bypassed; no credentials, token payment, or settlement audit is used."
|
|
868
901
|
].join("\n");
|
|
869
902
|
}
|
|
870
|
-
if (!
|
|
903
|
+
if (!snapshot.credentialsComplete) {
|
|
871
904
|
return `x402 rail is DORMANT. To activate: ${activation}`;
|
|
872
905
|
}
|
|
873
906
|
const settlement = [
|
|
@@ -904,7 +937,7 @@ function isTable(value) {
|
|
|
904
937
|
}
|
|
905
938
|
|
|
906
939
|
// src/cli/_deploy/deployCli.ts
|
|
907
|
-
var DEPLOY_CLI_VERSION = "0.5.
|
|
940
|
+
var DEPLOY_CLI_VERSION = "0.5.12";
|
|
908
941
|
var DEPLOY_CLI_PACKAGE = `@bnbagent/deploy-cli@${DEPLOY_CLI_VERSION}`;
|
|
909
942
|
var BNB_PLATFORM_API_URL = "https://bnbagent-api.bnbchain.world";
|
|
910
943
|
var BNB_PLATFORM_API_URL_ENV = "BNBAGENT_API_URL";
|
|
@@ -936,7 +969,8 @@ var FOUNDRY_PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
|
936
969
|
"project",
|
|
937
970
|
"projectEndpoint",
|
|
938
971
|
"protocol",
|
|
939
|
-
"registry"
|
|
972
|
+
"registry",
|
|
973
|
+
"subscriptionId"
|
|
940
974
|
]);
|
|
941
975
|
function tableOf(data, key) {
|
|
942
976
|
const v = data[key];
|
|
@@ -1054,7 +1088,8 @@ function buildDeploySpec(root, opts) {
|
|
|
1054
1088
|
["account_name", "account"],
|
|
1055
1089
|
["project_name", "project"],
|
|
1056
1090
|
["project_endpoint", "projectEndpoint"],
|
|
1057
|
-
["location", "location"]
|
|
1091
|
+
["location", "location"],
|
|
1092
|
+
["subscription_id", "subscriptionId"]
|
|
1058
1093
|
]) {
|
|
1059
1094
|
const value = String(azure[source] ?? "").trim();
|
|
1060
1095
|
if (value) {
|
|
@@ -1336,7 +1371,9 @@ export {
|
|
|
1336
1371
|
X402_CAPABLE_RUNTIMES,
|
|
1337
1372
|
commerceRails,
|
|
1338
1373
|
b402Credentials,
|
|
1374
|
+
x402DeploymentSnapshot,
|
|
1339
1375
|
x402DeploySummary,
|
|
1376
|
+
x402DeploySummaryFromSnapshot,
|
|
1340
1377
|
DEPLOY_CLI_VERSION,
|
|
1341
1378
|
DEPLOY_CLI_PACKAGE,
|
|
1342
1379
|
BNB_PLATFORM_API_URL,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/studio-cli",
|
|
3
|
-
"version": "0.0.11-alpha.
|
|
3
|
+
"version": "0.0.11-alpha.6",
|
|
4
4
|
"description": "Skills-first toolkit and bag CLI for BNB Chain seller agents: ERC-8004 identity, ERC-8183 escrowed commerce, and x402 payments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bnb-chain",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"tar": "^7.4.0",
|
|
55
55
|
"viem": "^2.54.0",
|
|
56
56
|
"yaml": "^2.9.0",
|
|
57
|
-
"@bnbagent/studio-runtime": "0.0.11-alpha.
|
|
57
|
+
"@bnbagent/studio-runtime": "0.0.11-alpha.6"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@a2a-js/sdk": "^0.3.14",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio
|
|
3
|
-
description: The single entry point for bnbagent-studio - a TypeScript CLI (`bag`) for building a blockchain SELLER agent that earns $U on BNB Chain via ERC-8004 + ERC-8183 + x402 (Pieverse LLM inside). Load this skill whenever the user works in a bnbagent-studio / `bag` project, or wants to create/scaffold, deploy, run, debug, operate, or monetize such a seller agent (composable A2A, MCP, and X402 faces; BNB Chain trial or
|
|
3
|
+
description: The single entry point for bnbagent-studio - a TypeScript CLI (`bag`) for building a blockchain SELLER agent that earns $U on BNB Chain via ERC-8004 + ERC-8183 + x402 (Pieverse LLM inside). Load this skill whenever the user works in a bnbagent-studio / `bag` project, or wants to create/scaffold, deploy, run, debug, operate, or monetize such a seller agent (composable A2A, MCP, and X402 faces; BNB Chain trial, AWS AgentCore, or Azure Foundry). All detailed playbooks ship as references/ files inside this skill - route via the decision tree in the body. When invoked with arguments, treat them as the user's intent and route the same way.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# bnbagent-studio (the single entry point)
|
|
7
7
|
|
|
8
|
-
`bnbagent-studio` (CLI: `bag`) wires the `@bnbagent/sdk` protocol layer (wallet / ERC-8004 / ERC-8183 / Pieverse LLM) into a TypeScript agent project, then deploys it as a **single blockchain seller runtime**. A2A, MCP, and X402 are composable public faces selected with `--protocols`; A2A is
|
|
8
|
+
`bnbagent-studio` (CLI: `bag`) wires the `@bnbagent/sdk` protocol layer (wallet / ERC-8004 / ERC-8183 / Pieverse LLM) into a TypeScript agent project, then deploys it as a **single blockchain seller runtime**. A2A, MCP, and X402 are composable public faces selected with `--protocols`; the default evm-local/twak scaffold serves A2A + X402 with both ERC-8183 and B402 rails, while Altana defaults to A2A + ERC-8183 because paid B402 is unsupported. `bag deploy` uses **scheme C**: every new deploy or redeploy explicitly selects BNB, AWS, or Azure; a recorded deployment is used only to offer an explicit update action, never as a silent default. BNB is a 48h testnet trial and is disabled after expiry. AWS and Azure self-deploy into the user's own account. All cloud lifecycle mutations go through the pinned `@bnbagent/deploy-cli`; the optional AWS CLI is used only by the fail-open, read-only AgentCore quota check in `bag deploy prepare`. AgentCore and Azure Foundry share the unified A2A/X402 entrypoint; Azure rejects MCP. Treat an incompatible provider row as unavailable-do not force through it or mutate the scaffold during deploy.
|
|
9
9
|
|
|
10
10
|
Invoked as `/bnbagent-studio <ask>`? Treat `<ask>` as the user's intent and route it through the decision tree below, exactly like a natural-language ask.
|
|
11
11
|
|
|
@@ -24,7 +24,7 @@ One deployed runtime, one signer: a single valuable Agent serves the selected fa
|
|
|
24
24
|
| Run / debug / dev / doctor / RPC / balance / incident triage | `references/bnbagent-studio-operating.md` |
|
|
25
25
|
| Implement what the Agent sells, tune pricing, publish over A2A and/or MCP, defend disputes (seller flow) | `references/bnbagent-studio-selling-via-8183.md` |
|
|
26
26
|
| Sell one paid or FREE HTTP request through the B402-backed x402 rail (pricing choice; paid merchant application, RSA key, credentials, IP allowlist, activation) | `references/bnbagent-studio-selling-via-b402.md` |
|
|
27
|
-
| Deploy / redeploy / status / logs / destroy | Run `bag deploy` and explicitly choose a provider. Non-interactive deploy requires `--provider bnb\|aws --yes` (and `--allow-multiple` when keeping another provider active). Read `references/bnbagent-studio-use-bnb-trial.md` or `references/bnbagent-studio-use-
|
|
27
|
+
| Deploy / redeploy / status / logs / destroy | Run `bag deploy` and explicitly choose a provider. Non-interactive deploy requires `--provider bnb\|aws\|azure --yes` (and `--allow-multiple` when keeping another provider active). Read `references/bnbagent-studio-use-bnb-trial.md`, `references/bnbagent-studio-use-aws-agentcore.md`, or `references/bnbagent-studio-use-azure-foundry.md` for the selected provider. `bag deploy status` lists every recorded provider; multi-deployment logs/verify/destroy require `--provider`. |
|
|
28
28
|
| Wire chain-read tools into the Agent's LLM (AI SDK `tool()` wrappers, or any TS agent framework) | `references/bnbagent-studio-wiring-llm-tools.md` |
|
|
29
29
|
| Buy a service from another ERC-8183 seller via CLI - incl. testing your own seller from the buyer side (v2/internal - NOT the v1 seller product flow) | `references/bnbagent-studio-buying-via-8183.md` |
|
|
30
30
|
| Give the agent a PAID x402 capability - CMC market data / Binance Bazaar (B402) merchants / any pay-per-call API (`bag x402 trust`, x402-buyer recipe, 402 buyer errors) | `references/bnbagent-studio-buying-from-bazaar.md` |
|
|
@@ -53,7 +53,7 @@ Treat ERC-8183 amounts as decimal strings at CLI/config boundaries and `bigint`
|
|
|
53
53
|
|
|
54
54
|
## CLI groups at a glance
|
|
55
55
|
|
|
56
|
-
`init`, `scan`, `recipe`, `skills`, `wallet`, `erc8004`, `erc8183`, `x402`, `agents`, `config`, `env`, `dev`, `doctor`, `audit`, `deploy`, `platform`, `llm`, `bundle`, `budget` - see `bag --help` for details. `bag deploy [--provider bnb\|aws] [--backend aws\|azure]` is the primary deploy command; `--backend` is valid only for provider `bnb` and confirms the recipe-derived managed backend. `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, and `fix-gitignore` remain lifecycle subcommands (`deploy agent` is a deprecated compatibility alias). Provider deploy/status/logs/destroy and deploy-time credential validation are delegated to pinned `@bnbagent/deploy-cli@0.5.
|
|
56
|
+
`init`, `scan`, `recipe`, `skills`, `wallet`, `erc8004`, `erc8183`, `x402`, `agents`, `config`, `env`, `dev`, `doctor`, `audit`, `deploy`, `platform`, `llm`, `bundle`, `budget` - see `bag --help` for details. `bag deploy [--provider bnb\|aws\|azure] [--backend aws\|azure]` is the primary deploy command; `--backend` is valid only for provider `bnb` and confirms the recipe-derived managed backend. `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, and `fix-gitignore` remain lifecycle subcommands (`deploy agent` is a deprecated compatibility alias). Provider deploy/status/logs/destroy and deploy-time credential validation are delegated to pinned `@bnbagent/deploy-cli@0.5.12`.
|
|
57
57
|
|
|
58
58
|
## Tool surface
|
|
59
59
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio-adding-to-project
|
|
3
|
-
description: When the user wants to add bnbagent-studio's single
|
|
3
|
+
description: When the user wants to add bnbagent-studio's single seller runtime (one valuable Agent on AWS Bedrock AgentCore that serves A2A + X402 with ERC-8183 + B402 by default, or another selected face/rail combination, holds the key, and signs in-process) to an existing TypeScript agent project.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio-scaffolding-agent
|
|
3
|
-
description: When the user wants to create a brand-new blockchain SELLER from zero - a single valuable Agent on AWS Bedrock AgentCore that serves A2A by default or
|
|
3
|
+
description: When the user wants to create a brand-new blockchain SELLER from zero - a single valuable Agent on AWS Bedrock AgentCore that serves A2A + X402 with ERC-8183 + B402 by default (or another selected face/rail combination), holds the key, and signs in-process. Drives the full intake → todo-list → execute flow.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
|
|
@@ -71,7 +71,7 @@ The fields (give the user all of them at once):
|
|
|
71
71
|
| 3 | **LLM provider** | `pieverse-llm` / `openrouter` / `openai` / `anthropic` / `bedrock` | `pieverse-llm` |
|
|
72
72
|
| 4 | **Wallet kind** (`--wallet-kind`) | `evm-local` (encrypted local keystore at the workspace root; `bag wallet new` creates it, `--private-key` imports an existing key; CodeZip deploy) / `twak` (**fully supported, opt in with `--wallet-kind twak`** - Trust Wallet Agent Kit CLI ≥0.20.0, self-custody encrypted mnemonic in a **project-dedicated** home `.studio/twak`, isolated from your main `~/.twak`; created manually with `HOME=<ws>/.studio/twak twak wallet create`, then `bag wallet new` adopts; container deploy. Reuse an existing wallet across agents with `--twak-home <path>`) / `altana` (bounded-session custody - admin keystore stays local, deploys ship ONLY the `ALTANA_SESSION` secret; zip deploy; not compatible with `pieverse-llm` or a paid b402 rail; flow: `references/bnbagent-studio-using-altana-wallet.md`) | `evm-local` |
|
|
73
73
|
| 5 | **Storage** | `local` (file:// on disk, offline dev only, does **NOT** survive deploy) / `ipfs` (durable, public, deploy-ready; needs your pinning service's upload endpoint + write key as `STORAGE_API_URL` / `STORAGE_API_KEY` in `.studio/.env.local` **before the first real delivery** - see Step 6b) | `local` |
|
|
74
|
-
| 6 | **Protocol faces** (`--protocols`) | any non-empty subset of `A2A`, `MCP`, `X402` | `A2A` |
|
|
74
|
+
| 6 | **Protocol faces** (`--protocols`) | any non-empty subset of `A2A`, `MCP`, `X402` | `A2A,X402` (`A2A` for Altana) |
|
|
75
75
|
| 7 | **LLM model** | provider catalogue; for `pieverse-llm` the default `auto/free` runs at $0/token | `auto/free` |
|
|
76
76
|
| 8 | **Auto-topup** | `enable` / `disable` - lets the Agent auto-pay $U from the wallet when LLM credits run low | deferred (non-interactive `bag init` records no `[budget]`; enable later with `bag budget enable`) |
|
|
77
77
|
| 9 | **Scaffold destination** (`--destination`) | `self` (prepare the AgentCore scaffold for **your own** AWS account; runtime material stays under your cloud-account control) / `platform` (prepare for a 48h **testnet-only** trial on the BNB Chain managed platform - runs the _same_ agent in the **operator's** AWS, so a wallet key **leaves your control**; it hard-forces `[network].default = bsc-testnet`, pins runtime=`agentcore`, packages an artifact, and auth is GitHub device flow. Use a **throwaway** `bag wallet new`, never your main wallet). This is scaffold intent only; deploy still explicitly selects `--provider`. | `platform` while the trial campaign runs (bare init falls back to `self` once it ends, or when `--network bsc-mainnet` / a non-agentcore `--runtime` is passed) |
|
|
@@ -86,7 +86,7 @@ v1 is **seller-only** - there is no role to choose. `bag init` scaffolds the sin
|
|
|
86
86
|
| --- | --- | --- |
|
|
87
87
|
| **Agent stack** | AI SDK (`ai`) | The library the agent's brain is built with - the emitted `src/model.ts` factory returns an AI SDK `LanguageModel`, and `src/tools.ts` wraps the chain reads as AI SDK `tool()`s. (There is no `--framework` flag: the old framework axis folded into the runtime templates.) |
|
|
88
88
|
| **Runtime** | `agentcore` | AWS Bedrock AgentCore - where the agent is hosted and served (`--runtime agentcore`). |
|
|
89
|
-
| **Protocol faces** | selected above (`A2A` default; MCP
|
|
89
|
+
| **Protocol faces** | selected above (`A2A,X402` default for evm-local/twak; `A2A` for Altana; MCP composable) | A2A hosts agent card + JSON-RPC on `:9000`; MCP-only hosts `/mcp` on `:8000`; A2A+MCP uses A2A-native `dualMain.ts` on `:9000` and tunnels buffered MCP through the platform; X402 adds `/x402`, and X402-only suppresses protocol discovery. |
|
|
90
90
|
|
|
91
91
|
**Not surfaced** (handled automatically, no need to show or ask):
|
|
92
92
|
|
|
@@ -138,7 +138,7 @@ Build a TodoWrite list. The shape depends on the `wallet kind`. The canonical 8-
|
|
|
138
138
|
|
|
139
139
|
> **Onboarding note.** On a human TTY, `bag init` runs steps 3, 4 and 6 automatically (it prompts once for the wallet password, runs `bag wallet new`, zero-deposit-activates Pieverse, and prints faucet URLs). **You (Claude Code) drive `bag init` non-interactively**, so that auto-flow does NOT fire - keep steps 3/4/6 below. Pass `--no-onboard` to `bag init` to make this explicit and deterministic regardless of how the shell wires stdin.
|
|
140
140
|
|
|
141
|
-
1. `bag init <name> --llm-provider <p> --network <n> --storage-provider <s> --wallet-kind <k> --rails <8183|b402|both> [--erc8183-price <base-units>] [--b402-price <usd>] --no-onboard` - scaffold the current workspace. **`<name>` must start with a letter, use ASCII letters and digits only, and be at most 23 characters.** `bag init` rejects `-`, `_`, `.`, and overlong names instead of renaming them. Pass `--wallet-kind evm-local` (default) or `--wallet-kind twak` (twak is fully supported - pass the flag to opt in), and `--storage-provider local` (default) or `ipfs`, per the Stage-1 choices; for twak, add `--twak-home <path>` ONLY if the user wants to reuse an existing wallet (otherwise omit - a project-dedicated `.studio/twak` is the safe default).
|
|
141
|
+
1. `bag init <name> --llm-provider <p> --network <n> --storage-provider <s> --wallet-kind <k> [--protocols <comma-list>] [--rails <8183|b402|both>] [--erc8183-price <base-units>] [--b402-price <usd>] --no-onboard` - scaffold the current workspace. **`<name>` must start with a letter, use ASCII letters and digits only, and be at most 23 characters.** `bag init` rejects `-`, `_`, `.`, and overlong names instead of renaming them. Pass `--wallet-kind evm-local` (default) or `--wallet-kind twak` (twak is fully supported - pass the flag to opt in), and `--storage-provider local` (default) or `ipfs`, per the Stage-1 choices; for twak, add `--twak-home <path>` ONLY if the user wants to reuse an existing wallet (otherwise omit - a project-dedicated `.studio/twak` is the safe default). Omit `--protocols` and `--rails` for the default A2A + X402 faces with both ERC-8183 and B402 rails; Altana instead defaults to A2A + ERC-8183 because paid B402 is unsupported. Pass either flag when the user chose another face/rail combination (`--protocol <one>` is only a legacy alias), add `--model <m>` only if the user overrode the provider default, and `--enable-auto-topup` / `--no-auto-topup` only if they made an explicit choice (otherwise omit - consent stays deferred). Pass `--erc8183-price 0` only when the user explicitly chose FREE; omitting the flag preserves the paid 0.1 U default. The canonical stack supports FREE; if a custom deployment is selected, set all three `ERC8183_COMMERCE_ADDRESS`, `ERC8183_ROUTER_ADDRESS`, and `ERC8183_POLICY_ADDRESS` values from that same stack. For B402, pass `--b402-price 0` only after the user explicitly accepts an unrestricted anonymous FREE `/x402` endpoint. FREE bypasses B402 verify/settle and needs no merchant credentials; a positive price keeps the `$0.01` default and requires the paid onboarding playbook. **Destination:** while the trial campaign runs, bare `bag init` (no `--destination`) defaults to `platform` - so pass `--destination self` **explicitly** whenever the user chose their own AWS, otherwise studio.toml silently records `platform` and the confirmation block you echoed no longer matches what was written. Omit `--destination` only when the user actually wants the `platform` 48h testnet trial (the campaign default) - do NOT treat that default as a mistake or re-confirm it; it is the intended behavior while the campaign is open. (Bare init also resolves to `self` once the campaign ends, or when `--network bsc-mainnet` / a non-agentcore `--runtime` is passed.) On the `platform` path `bag init` hard-forces `bsc-testnet`, pins `--runtime agentcore` + packages an artifact (a zip for the default evm-local and altana wallets, a container for twak). For evm-local a wallet key will later leave your machine, so pair it with a throwaway `bag wallet new`; for altana only the bounded session ships - do NOT create a new wallet (full flow: `docs/guides/platform-deploy.md`). Defaults `--runtime agentcore` (the only advertised runtime; the Preview `azure-foundry` runtime remains explicitly selectable but is outside this playbook; there is no `--framework` flag because the AI SDK model/tools story is part of the runtime templates). Creates `<name>/` workspace root + `<name>/app/agent/` (the single sub-project: A2A emits `src/unifiedMain.ts` (the express + A2A entrypoint, one code set for both deploy clouds) + `src/sellerCore.ts` (the protocol-neutral core; executor inherits it) + `src/executor.ts` + `src/agentCard.ts`; MCP emits `src/mcpMain.ts`; both include `src/signing.ts` + `src/tools.ts` + `src/model.ts` + their own `studio.toml` + `package.json` + `tsconfig.json`) + `<name>/agentcore/` (`agentcore.json` + `aws-targets.json`, self-rendered - no agentcore CLI needed at init). The workspace root holds the `agentcore/` deploy descriptor, the `.studio/wallets/` keystore, a thin `package.json` + `pnpm-workspace.yaml`, README, and `.gitignore`. (v1 is seller-only - no `--role`.)
|
|
142
142
|
> **Altana + custom contracts:** Altana sessions remain bound to the canonical ERC-8183 targets. Use `evm-local` for a custom Commerce/Router/Policy stack; doctor and deploy readiness reject this unsupported combination when the ERC-8183 rail is active.
|
|
143
143
|
|
|
144
144
|
2. `cd <name>`, then make sure the dependencies are installed. `bag init` already runs the install by default (skip only if it was scaffolded with `--no-install`); the manual equivalent from the workspace root is:
|
|
@@ -7,7 +7,7 @@ description: When the user is acting as an ERC-8183 seller on the single selecte
|
|
|
7
7
|
|
|
8
8
|
# bnbagent-studio-selling-via-8183
|
|
9
9
|
|
|
10
|
-
Procedure for the **single seller flow**: implement the value your Agent produces, deploy it to AgentCore (where
|
|
10
|
+
Procedure for the **single seller flow**: implement the value your Agent produces, deploy it to AgentCore (where the default scaffold serves A2A + X402, while ERC-8183 remains available through A2A or an explicitly selected MCP face), and handle the job lifecycle (Agent quotes → buyer funds → buyer calls `notify_funded` → Agent delivers → buyer reads the result from the chain → buyer settles or disputes).
|
|
11
11
|
|
|
12
12
|
Audience: Claude Code in a working repo with a funded wallet (tBNB + U) and an Agent that produces some valuable output (text, classification, image - whatever).
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio-use-aws-agentcore
|
|
3
|
-
description: When the user wants to deploy or operate a bnbagent-studio project on AWS Bedrock AgentCore - deploy with `bag deploy --provider aws` (all cloud lifecycle mutations are delegated to pinned `@bnbagent/deploy-cli@0.5.
|
|
3
|
+
description: When the user wants to deploy or operate a bnbagent-studio project on AWS Bedrock AgentCore - deploy with `bag deploy --provider aws` (all cloud lifecycle mutations are delegated to pinned `@bnbagent/deploy-cli@0.5.12`), inspect with `bag deploy status` / `logs --provider aws` / `verify --provider aws`, and tear down with `bag deploy destroy --provider aws --execute [--purge]`. Also covers AWS credential prerequisites, the optional read-only quota probe, and the runtime-secret channel.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio-use-azure-foundry
|
|
3
|
-
description: When the user wants to deploy or operate a bnbagent-studio project on Azure AI Foundry Hosted Agents - scaffold with `bag init --runtime azure-foundry`, deploy either to the managed platform with `bag deploy --provider bnb --backend azure` or directly with `bag deploy --provider azure`; all cloud lifecycle execution is delegated to pinned `@bnbagent/deploy-cli@0.5.
|
|
3
|
+
description: When the user wants to deploy or operate a bnbagent-studio project on Azure AI Foundry Hosted Agents - scaffold with `bag init --runtime azure-foundry`, deploy either to the managed platform with `bag deploy --provider bnb --backend azure` or directly with `bag deploy --provider azure`; all cloud lifecycle execution is delegated to pinned `@bnbagent/deploy-cli@0.5.12`. Native MCP is not supported on Azure; use AgentCore for MCP.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
|
|
@@ -16,7 +16,7 @@ Procedure for deploying and operating the seller Agent on **Azure AI Foundry Hos
|
|
|
16
16
|
```
|
|
17
17
|
<workspace>/
|
|
18
18
|
├── app/agent/ # the deployed code (src/unifiedMain.ts host + Dockerfile here)
|
|
19
|
-
│ ├── studio.toml # [azure] block: location / account_name / subdomain / project_name / agent_endpoint
|
|
19
|
+
│ ├── studio.toml # [azure] block: location / subscription_id / account_name / subdomain / project_name / agent_endpoint
|
|
20
20
|
│ └── Dockerfile # the container image bnbagent-deploy builds + pushes
|
|
21
21
|
└── .studio/ # secrets + wallets (workspace root - never in the image)
|
|
22
22
|
```
|
|
@@ -31,7 +31,7 @@ Procedure for deploying and operating the seller Agent on **Azure AI Foundry Hos
|
|
|
31
31
|
|
|
32
32
|
1. **Bun 1.3+ (`bunx`) on PATH** - the pinned `@bnbagent/deploy-cli` runs through it.
|
|
33
33
|
2. **Docker running** - the image is built locally (linux/amd64) before push.
|
|
34
|
-
3. **An Azure subscription** the operator may provision in (Foundry account/project, container registry, hosted agent). Before a local self-deploy, run `bunx --bun @bnbagent/deploy-cli@0.5.
|
|
34
|
+
3. **An Azure subscription** the operator may provision in (Foundry account/project, container registry, hosted agent). Before a local self-deploy, run `bunx --bun @bnbagent/deploy-cli@0.5.12 login --provider azure`; use OIDC/service-principal credentials in CI.
|
|
35
35
|
|
|
36
36
|
## ⚠️ Foundry gotchas (read before deploying)
|
|
37
37
|
|
|
@@ -49,7 +49,7 @@ Procedure for deploying and operating the seller Agent on **Azure AI Foundry Hos
|
|
|
49
49
|
|
|
50
50
|
> The encrypted keystore (`.studio/wallets/`) stays at the workspace root and rides only that secret channel - never baked into the image.
|
|
51
51
|
|
|
52
|
-
Provider-native overrides go in the optional `studio.toml [deploy.foundry]` table (verbatim deploy-spec keys; deploy-cli 0.5.
|
|
52
|
+
Provider-native overrides go in the optional `studio.toml [deploy.foundry]` table (verbatim deploy-spec keys; deploy-cli 0.5.12 consumes `account`, `cpu`, `location`, `memory`, `project`, `projectEndpoint`, `protocol`, `registry`, `subscriptionId` and warns about anything else). The `[azure]` block's `subscription_id` / `account_name` / `project_name` / `project_endpoint` / `location` win over conflicting `[deploy.foundry]` keys.
|
|
53
53
|
|
|
54
54
|
## Typical workflow
|
|
55
55
|
|
|
@@ -76,8 +76,9 @@ bag deploy --provider azure # delegated: onboard → build+push
|
|
|
76
76
|
|
|
77
77
|
For a first deploy in non-interactive automation, pass `--yes`. Studio treats
|
|
78
78
|
that as confirmation of the full deployment plan and delegates explicit
|
|
79
|
-
Foundry project onboarding. Configure `[azure]`
|
|
80
|
-
when several candidates are accessible so no prompt or guess is
|
|
79
|
+
Foundry project onboarding. Configure `[azure].subscription_id` and
|
|
80
|
+
`account_name` when several candidates are accessible so no prompt or guess is
|
|
81
|
+
required.
|
|
81
82
|
|
|
82
83
|
### C. Validate / operate
|
|
83
84
|
|
|
@@ -138,6 +139,6 @@ Azure Foundry is an alternate runtime for the whole seller agent. There is no se
|
|
|
138
139
|
## Reference
|
|
139
140
|
|
|
140
141
|
- `bag deploy --help` / `bag deploy <command> --help` (authoritative for commands + flags)
|
|
141
|
-
- `app/agent/studio.toml [azure]` - location / account_name / subdomain / project_name / agent_endpoint
|
|
142
|
+
- `app/agent/studio.toml [azure]` - location / subscription_id / account_name / subdomain / project_name / agent_endpoint
|
|
142
143
|
- `app/agent/studio.toml [deploy.foundry]` - provider-native deploy-spec passthrough
|
|
143
144
|
- `BNBAGENT_DEPLOY_COMMAND` - override the pinned `bunx --bun @bnbagent/deploy-cli@<pin>` invocation (E2E/dev)
|
|
@@ -9,7 +9,7 @@ description: Use when deploying or operating a bnbagent-studio seller on the BNB
|
|
|
9
9
|
|
|
10
10
|
Treat this provider as a temporary testnet sandbox. Require a throwaway wallet, keep `bsc-testnet`, and explain that the runtime signing material is transmitted to the operator's managed secret store for the trial. Never use a mainnet key. Exception: `wallet.kind='altana'` ships only the bounded, budget-limited, revocable session - the throwaway-wallet advice does not apply; tighten the session instead (`bag wallet session grant --force --budget-u <small> --expiry-days <short>`) and never run `bag wallet new` on an altana project (it breaks the session's `[wallet].address` anchor).
|
|
11
11
|
|
|
12
|
-
All auth and cloud lifecycle work must cross the pinned `@bnbagent/deploy-cli@0.5.
|
|
12
|
+
All auth and cloud lifecycle work must cross the pinned `@bnbagent/deploy-cli@0.5.12` boundary. Do not call a cloud CLI or platform REST routes directly. The managed backend is recipe-derived: `agentcore` uses AWS; `azure-foundry` uses Azure. For headless managed Azure, confirm with `bag deploy --provider bnb --backend azure --yes`; never treat `--backend` as a cross-cloud recipe converter.
|
|
13
13
|
|
|
14
14
|
## Select and authenticate
|
|
15
15
|
|