@bnbagent/studio-cli 0.0.6-alpha.6 → 0.0.6-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bag.js +205 -76
- package/package.json +2 -2
- package/skills/bnbagent-studio.md +1 -1
- package/skills/references/bnbagent-studio-adding-to-project.md +6 -6
- package/skills/references/bnbagent-studio-operating.md +1 -2
- package/skills/references/bnbagent-studio-scaffolding-agent.md +8 -9
- package/skills/references/bnbagent-studio-selling-via-8183.md +3 -4
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +12 -14
package/dist/bag.js
CHANGED
|
@@ -4284,6 +4284,7 @@ import {
|
|
|
4284
4284
|
import { getNetwork as getNetwork4 } from "@bnbagent/studio-runtime/networks";
|
|
4285
4285
|
import * as pieverseRt from "@bnbagent/studio-runtime/pieverse";
|
|
4286
4286
|
import {
|
|
4287
|
+
PieverseKeyNotFoundError,
|
|
4287
4288
|
PieversePolicy,
|
|
4288
4289
|
RetryPolicy,
|
|
4289
4290
|
allocateWithSettleRetry,
|
|
@@ -4417,7 +4418,10 @@ function registerLlm(program) {
|
|
|
4417
4418
|
).option(
|
|
4418
4419
|
"--network <name>",
|
|
4419
4420
|
"Override [llm.pieverse].network (e.g. bsc-mainnet, bsc-testnet)."
|
|
4420
|
-
).option("--name <name>", "Key name (default: bnbagent-studio-default).").
|
|
4421
|
+
).option("--name <name>", "Key name (default: bnbagent-studio-default).").option(
|
|
4422
|
+
"--replace",
|
|
4423
|
+
"Ignore any existing key and mint a fresh one, overwriting PIEVERSE_LLM_API_KEY in .studio/.env.local. Use when the key you inherited (e.g. from a shared env file) no longer exists in Pieverse. The old key is left untouched on the Pieverse side."
|
|
4424
|
+
).action(
|
|
4421
4425
|
act(
|
|
4422
4426
|
(opts) => cmdActivate(opts)
|
|
4423
4427
|
)
|
|
@@ -4626,9 +4630,20 @@ async function cmdActivate(opts) {
|
|
|
4626
4630
|
return 2;
|
|
4627
4631
|
}
|
|
4628
4632
|
const pvCfg = loadPieverseConfig(cfg);
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
const
|
|
4633
|
+
const replace = opts.replace === true;
|
|
4634
|
+
let existingHash = !replace && pvCfg.key_hash ? String(pvCfg.key_hash) : null;
|
|
4635
|
+
const envFileValue = replace ? null : getEnvVar(envLocalPath9(root), PIEVERSE_ENV_KEY);
|
|
4636
|
+
const existingEnv = replace ? null : envFileValue || process.env[PIEVERSE_ENV_KEY];
|
|
4637
|
+
if (replace) {
|
|
4638
|
+
printOut(
|
|
4639
|
+
`\u2192 --replace: ignoring any existing ${PIEVERSE_ENV_KEY} and minting a fresh key\u2026`
|
|
4640
|
+
);
|
|
4641
|
+
if (process.env[PIEVERSE_ENV_KEY]) {
|
|
4642
|
+
printErr(
|
|
4643
|
+
`warning: ${PIEVERSE_ENV_KEY} is also exported in this shell. The new key goes to .studio/.env.local, which \`bag\` prefers, but \`unset ${PIEVERSE_ENV_KEY}\` to keep the two from diverging.`
|
|
4644
|
+
);
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4632
4647
|
if (!existingHash && existingEnv) {
|
|
4633
4648
|
const derivedHash = pieverseKeyHash(existingEnv);
|
|
4634
4649
|
printOut(
|
|
@@ -4637,15 +4652,24 @@ async function cmdActivate(opts) {
|
|
|
4637
4652
|
try {
|
|
4638
4653
|
await withSiweRetry(wallet, (token) => inspectKey(token, derivedHash));
|
|
4639
4654
|
} catch (exc) {
|
|
4655
|
+
if (!(exc instanceof PieverseKeyNotFoundError)) {
|
|
4656
|
+
printErr(
|
|
4657
|
+
`error: could not verify the existing ${PIEVERSE_ENV_KEY} against Pieverse: ${errMessage(
|
|
4658
|
+
exc
|
|
4659
|
+
)}
|
|
4660
|
+
The existing key was kept and no new key was created. This looks like a transport or login failure rather than a missing key \u2014 retry \`bag llm activate\` once Pieverse is reachable.`
|
|
4661
|
+
);
|
|
4662
|
+
return 2;
|
|
4663
|
+
}
|
|
4640
4664
|
const sources = [
|
|
4641
4665
|
envFileValue ? `.studio/.env.local (a ${PIEVERSE_ENV_KEY}= line)` : "",
|
|
4642
4666
|
process.env[PIEVERSE_ENV_KEY] ? "the shell environment" : ""
|
|
4643
4667
|
].filter(Boolean).join(" and ");
|
|
4644
4668
|
printErr(
|
|
4645
|
-
`error: ${PIEVERSE_ENV_KEY} already exists but
|
|
4669
|
+
`error: ${PIEVERSE_ENV_KEY} already exists but Pieverse does not know its key_hash: ${errMessage(
|
|
4646
4670
|
exc
|
|
4647
4671
|
)}
|
|
4648
|
-
The existing key was kept and no new key was created. The key comes from ${sources}
|
|
4672
|
+
The existing key was kept and no new key was created. The key comes from ${sources}. Re-run \`bag llm activate --replace\` to mint a fresh key and overwrite .studio/.env.local (then \`unset ${PIEVERSE_ENV_KEY}\` if you also exported it in this shell). (\`bag llm rotate\` replaces a key that is still valid in Pieverse; it cannot recover this one.)`
|
|
4649
4673
|
);
|
|
4650
4674
|
return 2;
|
|
4651
4675
|
}
|
|
@@ -11366,6 +11390,84 @@ async function checkAwsTargetsPopulated(root, target) {
|
|
|
11366
11390
|
}
|
|
11367
11391
|
];
|
|
11368
11392
|
}
|
|
11393
|
+
var AGENTCORE_AGENT_QUOTA_CODE = "L-F4575653";
|
|
11394
|
+
function awsJson(stdout) {
|
|
11395
|
+
try {
|
|
11396
|
+
const parsed = JSON.parse(stdout);
|
|
11397
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
11398
|
+
} catch {
|
|
11399
|
+
return null;
|
|
11400
|
+
}
|
|
11401
|
+
}
|
|
11402
|
+
async function checkAgentcoreQuotaHeadroom(root, target) {
|
|
11403
|
+
if (target !== "agentcore") {
|
|
11404
|
+
return [];
|
|
11405
|
+
}
|
|
11406
|
+
const [, region] = readAwsTarget(root);
|
|
11407
|
+
if (!region || !await whichBin("aws")) {
|
|
11408
|
+
return [];
|
|
11409
|
+
}
|
|
11410
|
+
const quotaRes = await runCapture("aws", [
|
|
11411
|
+
"service-quotas",
|
|
11412
|
+
"get-service-quota",
|
|
11413
|
+
"--service-code",
|
|
11414
|
+
"bedrock-agentcore",
|
|
11415
|
+
"--quota-code",
|
|
11416
|
+
AGENTCORE_AGENT_QUOTA_CODE,
|
|
11417
|
+
"--region",
|
|
11418
|
+
region,
|
|
11419
|
+
"--output",
|
|
11420
|
+
"json"
|
|
11421
|
+
]);
|
|
11422
|
+
if (quotaRes.code !== 0) {
|
|
11423
|
+
return [];
|
|
11424
|
+
}
|
|
11425
|
+
const quota = awsJson(quotaRes.stdout)?.Quota;
|
|
11426
|
+
const limit = typeof quota?.Value === "number" ? quota.Value : null;
|
|
11427
|
+
if (limit === null) {
|
|
11428
|
+
return [];
|
|
11429
|
+
}
|
|
11430
|
+
const listRes = await runCapture("aws", [
|
|
11431
|
+
"bedrock-agentcore-control",
|
|
11432
|
+
"list-agent-runtimes",
|
|
11433
|
+
"--region",
|
|
11434
|
+
region,
|
|
11435
|
+
"--output",
|
|
11436
|
+
"json"
|
|
11437
|
+
]);
|
|
11438
|
+
if (listRes.code !== 0) {
|
|
11439
|
+
return [];
|
|
11440
|
+
}
|
|
11441
|
+
const runtimes = awsJson(listRes.stdout)?.agentRuntimes;
|
|
11442
|
+
if (!Array.isArray(runtimes)) {
|
|
11443
|
+
return [];
|
|
11444
|
+
}
|
|
11445
|
+
const used = runtimes.length;
|
|
11446
|
+
const details = {
|
|
11447
|
+
used,
|
|
11448
|
+
limit,
|
|
11449
|
+
region,
|
|
11450
|
+
quota_code: AGENTCORE_AGENT_QUOTA_CODE
|
|
11451
|
+
};
|
|
11452
|
+
if (used < limit) {
|
|
11453
|
+
return [
|
|
11454
|
+
{
|
|
11455
|
+
level: Level.INFO,
|
|
11456
|
+
name: "agentcore_quota_headroom",
|
|
11457
|
+
message: `AgentCore runtimes: ${used}/${limit} used in ${region}.`,
|
|
11458
|
+
details
|
|
11459
|
+
}
|
|
11460
|
+
];
|
|
11461
|
+
}
|
|
11462
|
+
return [
|
|
11463
|
+
{
|
|
11464
|
+
level: Level.CRITICAL,
|
|
11465
|
+
name: "agentcore_quota_headroom",
|
|
11466
|
+
message: `AgentCore runtimes: ${used}/${limit} used in ${region} \u2014 no slots left, so the deploy would fail with \`maxAgents limit exceeded\` AFTER pushing the image and creating the secret, M2M client, and execution role (all orphans). Delete a runtime you no longer need (\`bag deploy destroy\` in its workspace) or request a quota increase for ${AGENTCORE_AGENT_QUOTA_CODE} ("Total Agents per Account") in the Service Quotas console.`,
|
|
11467
|
+
details
|
|
11468
|
+
}
|
|
11469
|
+
];
|
|
11470
|
+
}
|
|
11369
11471
|
var allChecks = [
|
|
11370
11472
|
checkAgentcoreJsonPresent,
|
|
11371
11473
|
checkAgentcoreAuthorizerKeyLegacy,
|
|
@@ -11390,7 +11492,8 @@ var allChecks = [
|
|
|
11390
11492
|
checkCommerceReady,
|
|
11391
11493
|
checkDeployCliRunnable,
|
|
11392
11494
|
checkRuntimeSecretsInjected,
|
|
11393
|
-
checkAwsTargetsPopulated
|
|
11495
|
+
checkAwsTargetsPopulated,
|
|
11496
|
+
checkAgentcoreQuotaHeadroom
|
|
11394
11497
|
];
|
|
11395
11498
|
|
|
11396
11499
|
// src/cli/_deploy/secrets.ts
|
|
@@ -11674,6 +11777,12 @@ function cognitoPackageJson() {
|
|
|
11674
11777
|
function readme() {
|
|
11675
11778
|
return `# Cognito M2M client for the AgentCore A2A inbound OAuth2 authorizer
|
|
11676
11779
|
|
|
11780
|
+
> **DEPRECATED.** \`bag deploy --provider aws\` now provisions its own user pool
|
|
11781
|
+
> and M2M client, and overwrites the values wired from this stack. Deploying
|
|
11782
|
+
> this app leaves a second, unused pool behind that you have to clean up
|
|
11783
|
+
> yourself. Keep it only if you need to own the pool out of band; otherwise run
|
|
11784
|
+
> \`bag deploy --provider aws\` and hand buyers the credentials it prints.
|
|
11785
|
+
|
|
11677
11786
|
AgentCore A2A endpoints REQUIRE inbound auth (there is no anonymous mode). This
|
|
11678
11787
|
seller uses **OAuth2 via Cognito** \u2014 NOT SigV4, because external buyers cannot
|
|
11679
11788
|
obtain your AWS IAM credentials. Cognito has no public machine-to-machine
|
|
@@ -11714,12 +11823,11 @@ This reads the local \`cdk-outputs.json\` and patches:
|
|
|
11714
11823
|
| \`Scope\` | \`agentcore.json\` \u2192 \`envVars[] OAUTH_SCOPE\` (+ \`.studio/.env.local\` for local dev) |
|
|
11715
11824
|
|
|
11716
11825
|
\`OAUTH_TOKEN_URL\` / \`OAUTH_SCOPE\` are read by the emitted agent card from
|
|
11717
|
-
the environment, so the
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
custom outputs path.)
|
|
11826
|
+
the environment, so the agent card advertises the OAuth2 security scheme buyers
|
|
11827
|
+
must use. **A \`bag deploy\` run replaces both values (and the authorizer) with
|
|
11828
|
+
the pool it provisions itself**, so this wiring only takes effect for local
|
|
11829
|
+
\`bag dev\`. (\`bag deploy provision-cognito --wire <file>\` accepts a custom
|
|
11830
|
+
outputs path.)
|
|
11723
11831
|
|
|
11724
11832
|
## Issue buyer credentials
|
|
11725
11833
|
|
|
@@ -11770,7 +11878,8 @@ function wireSummary(r) {
|
|
|
11770
11878
|
allowedClients = [${r.clientId}]
|
|
11771
11879
|
- ${path26.basename(r.agentcoreJson)}: envVars[] OAUTH_TOKEN_URL + OAUTH_SCOPE (reach the runtime so the agent card advertises oauth2)
|
|
11772
11880
|
- ${r.envLocal}: same pair, for local \`bag dev\`
|
|
11773
|
-
\u2192 \`bag deploy
|
|
11881
|
+
\u2192 NOTE: a \`bag deploy\` run provisions its own pool and overwrites these
|
|
11882
|
+
values with the ones it issued. This wiring only feeds local \`bag dev\`.`;
|
|
11774
11883
|
}
|
|
11775
11884
|
function flattenCdkOutputs(raw) {
|
|
11776
11885
|
const flat = {};
|
|
@@ -11798,6 +11907,49 @@ function upsertDescriptorEnvvars(cfg, values) {
|
|
|
11798
11907
|
}
|
|
11799
11908
|
}
|
|
11800
11909
|
}
|
|
11910
|
+
function syncDescriptorOauthFacts(workspaceRoot, facts) {
|
|
11911
|
+
const acj = path26.join(workspaceRoot, "agentcore", "agentcore.json");
|
|
11912
|
+
let cfg;
|
|
11913
|
+
try {
|
|
11914
|
+
cfg = JSON.parse(fs27.readFileSync(acj, "utf-8"));
|
|
11915
|
+
} catch {
|
|
11916
|
+
return;
|
|
11917
|
+
}
|
|
11918
|
+
const envValues = {};
|
|
11919
|
+
if (facts.tokenUrl) {
|
|
11920
|
+
envValues.OAUTH_TOKEN_URL = facts.tokenUrl;
|
|
11921
|
+
}
|
|
11922
|
+
if (facts.scope) {
|
|
11923
|
+
envValues.OAUTH_SCOPE = facts.scope;
|
|
11924
|
+
}
|
|
11925
|
+
const authorizer = facts.discoveryUrl && facts.clientId ? {
|
|
11926
|
+
customJwtAuthorizer: {
|
|
11927
|
+
discoveryUrl: facts.discoveryUrl,
|
|
11928
|
+
allowedClients: [facts.clientId]
|
|
11929
|
+
}
|
|
11930
|
+
} : null;
|
|
11931
|
+
if (Object.keys(envValues).length === 0 && authorizer === null) {
|
|
11932
|
+
return;
|
|
11933
|
+
}
|
|
11934
|
+
if (Object.keys(envValues).length > 0) {
|
|
11935
|
+
upsertDescriptorEnvvars(cfg, envValues);
|
|
11936
|
+
}
|
|
11937
|
+
if (authorizer !== null && Array.isArray(cfg.runtimes)) {
|
|
11938
|
+
for (const rt of cfg.runtimes) {
|
|
11939
|
+
if (rt !== null && typeof rt === "object") {
|
|
11940
|
+
const r = rt;
|
|
11941
|
+
r.authorizerType = "CUSTOM_JWT";
|
|
11942
|
+
r.authorizerConfiguration = authorizer;
|
|
11943
|
+
}
|
|
11944
|
+
}
|
|
11945
|
+
}
|
|
11946
|
+
try {
|
|
11947
|
+
fs27.writeFileSync(acj, `${JSON.stringify(cfg, null, 2)}
|
|
11948
|
+
`, "utf-8");
|
|
11949
|
+
} catch {
|
|
11950
|
+
return;
|
|
11951
|
+
}
|
|
11952
|
+
}
|
|
11801
11953
|
function upsertEnv(envLocal, values) {
|
|
11802
11954
|
let lines = [];
|
|
11803
11955
|
try {
|
|
@@ -12725,59 +12877,6 @@ async function checkInstalledRecipesUnchanged(root, _target) {
|
|
|
12725
12877
|
}
|
|
12726
12878
|
return [];
|
|
12727
12879
|
}
|
|
12728
|
-
function agentcoreAuthorizer(root) {
|
|
12729
|
-
const descriptor = path32.join(root, "agentcore", "agentcore.json");
|
|
12730
|
-
let data;
|
|
12731
|
-
try {
|
|
12732
|
-
data = JSON.parse(fs33.readFileSync(descriptor, "utf-8"));
|
|
12733
|
-
} catch {
|
|
12734
|
-
return null;
|
|
12735
|
-
}
|
|
12736
|
-
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
12737
|
-
return null;
|
|
12738
|
-
}
|
|
12739
|
-
const runtimes = data.runtimes;
|
|
12740
|
-
if (!Array.isArray(runtimes)) {
|
|
12741
|
-
return null;
|
|
12742
|
-
}
|
|
12743
|
-
for (const rt of runtimes) {
|
|
12744
|
-
if (rt === null || typeof rt !== "object") {
|
|
12745
|
-
continue;
|
|
12746
|
-
}
|
|
12747
|
-
const auth = rt.authorizerConfiguration;
|
|
12748
|
-
if (auth !== null && typeof auth === "object" && !Array.isArray(auth)) {
|
|
12749
|
-
const jwt = auth.customJwtAuthorizer ?? auth.customJWTAuthorizer;
|
|
12750
|
-
if (jwt !== null && typeof jwt === "object" && !Array.isArray(jwt)) {
|
|
12751
|
-
return jwt;
|
|
12752
|
-
}
|
|
12753
|
-
}
|
|
12754
|
-
}
|
|
12755
|
-
return null;
|
|
12756
|
-
}
|
|
12757
|
-
async function checkCognitoAuthorizerConfigured(root, target) {
|
|
12758
|
-
if (target !== "agentcore") {
|
|
12759
|
-
return [];
|
|
12760
|
-
}
|
|
12761
|
-
const jwt = agentcoreAuthorizer(root);
|
|
12762
|
-
const discovery = jwt?.discoveryUrl;
|
|
12763
|
-
const clients = jwt?.allowedClients;
|
|
12764
|
-
const configured = Boolean(discovery) && Array.isArray(clients) && clients.length > 0;
|
|
12765
|
-
if (configured) {
|
|
12766
|
-
return [];
|
|
12767
|
-
}
|
|
12768
|
-
return [
|
|
12769
|
-
{
|
|
12770
|
-
level: Level.WARNING,
|
|
12771
|
-
name: "cognito_authorizer_configured",
|
|
12772
|
-
message: "no Cognito authorizer configured in agentcore.json (authorizerConfiguration.customJwtAuthorizer.discoveryUrl/allowedClients) \u2192 the A2A endpoint will require SigV4/AWS creds; external buyers can't reach it. Run `bag deploy provision-cognito`, then paste the CDK outputs into the authorizer.",
|
|
12773
|
-
fixCmd: "bag deploy provision-cognito",
|
|
12774
|
-
details: {
|
|
12775
|
-
discovery_url_set: Boolean(discovery),
|
|
12776
|
-
allowed_clients: Array.isArray(clients) ? clients : []
|
|
12777
|
-
}
|
|
12778
|
-
}
|
|
12779
|
-
];
|
|
12780
|
-
}
|
|
12781
12880
|
async function checkStorageLocalNotDeployable(root, _target) {
|
|
12782
12881
|
const storage = loadAgentToml(root).storage;
|
|
12783
12882
|
if (storage === null || typeof storage !== "object" || Array.isArray(storage) || String(storage.kind ?? "").toLowerCase() !== "local") {
|
|
@@ -12802,7 +12901,6 @@ var allChecks4 = [
|
|
|
12802
12901
|
checkRpcUrlSetForRuntime,
|
|
12803
12902
|
checkRuntimeRpcReachable,
|
|
12804
12903
|
checkInstalledRecipesUnchanged,
|
|
12805
|
-
checkCognitoAuthorizerConfigured,
|
|
12806
12904
|
checkStorageLocalNotDeployable
|
|
12807
12905
|
];
|
|
12808
12906
|
|
|
@@ -13256,6 +13354,7 @@ function baseResult(endpoint, runtime, overrides) {
|
|
|
13256
13354
|
studioTomlUpdated: false,
|
|
13257
13355
|
runtime,
|
|
13258
13356
|
note: null,
|
|
13357
|
+
warning: null,
|
|
13259
13358
|
error: null,
|
|
13260
13359
|
exitCode: 0,
|
|
13261
13360
|
...overrides
|
|
@@ -13311,6 +13410,7 @@ async function runVerify(opts) {
|
|
|
13311
13410
|
let action = "none";
|
|
13312
13411
|
let registerError = null;
|
|
13313
13412
|
let postWriteError = null;
|
|
13413
|
+
let postWriteWarning = null;
|
|
13314
13414
|
let registerNote = null;
|
|
13315
13415
|
let identityPendingReason = null;
|
|
13316
13416
|
let registerExitCode = 0;
|
|
@@ -13343,9 +13443,8 @@ async function runVerify(opts) {
|
|
|
13343
13443
|
const cause = e.cause !== null && typeof e.cause === "object" ? e.cause : null;
|
|
13344
13444
|
const relayTxHash = typeof cause?.txHash === "string" ? cause.txHash : e.txHash;
|
|
13345
13445
|
action = "register_partial";
|
|
13346
|
-
|
|
13446
|
+
postWriteWarning = relayTxHash ? `ERC-8004 register created agent_id=${e.agentId}, but setAgentURI relay tx_hash=${relayTxHash} was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.` : `ERC-8004 register created agent_id=${e.agentId}, but the setAgentURI relay submission was not observed by the chain RPC. Run \`bag erc8004 clear-pending\` to reconcile, then retry \`bag erc8004 update-endpoint\`.`;
|
|
13347
13447
|
identityPendingReason = "setAgentURI relay submission unverified; run bag erc8004 clear-pending before retrying";
|
|
13348
|
-
registerExitCode = 1;
|
|
13349
13448
|
} else if (e.txHash) {
|
|
13350
13449
|
action = "register_pending";
|
|
13351
13450
|
registerNote = `ERC-8004 register created agent_id=${e.agentId}; setAgentURI tx pending (${e.txHash}). Check the tx before retrying \`bag erc8004 update-endpoint\`.`;
|
|
@@ -13439,6 +13538,7 @@ async function runVerify(opts) {
|
|
|
13439
13538
|
action,
|
|
13440
13539
|
studioTomlUpdated,
|
|
13441
13540
|
note: notes.length > 0 ? notes.join(" | ") : null,
|
|
13541
|
+
warning: postWriteWarning,
|
|
13442
13542
|
error: postWriteError,
|
|
13443
13543
|
exitCode: registerExitCode
|
|
13444
13544
|
});
|
|
@@ -14548,8 +14648,8 @@ function registerDeploy(program) {
|
|
|
14548
14648
|
p.command("fix-gitignore").description(
|
|
14549
14649
|
"Ensure the workspace .gitignore excludes .studio/ (the agent's .env.local + keystore)."
|
|
14550
14650
|
).option("--project-root <path>", "Override project root.").action(act((opts) => cmdFixGitignore(opts)));
|
|
14551
|
-
p.command("provision-cognito").description(
|
|
14552
|
-
"Emit an AWS CDK app under agentcore/cognito/ that provisions a Cognito M2M client for the AgentCore
|
|
14651
|
+
p.command("provision-cognito", { hidden: true }).description(
|
|
14652
|
+
"DEPRECATED \u2014 `bag deploy` provisions inbound OAuth by itself. Emit an AWS CDK app under agentcore/cognito/ that provisions a Cognito M2M client for the AgentCore inbound OAuth2 authorizer (studio writes IaC + prints steps; you run `cdk deploy`)."
|
|
14553
14653
|
).option("--project-root <path>", "Override project root.").option(
|
|
14554
14654
|
"--wire [outputsFile]",
|
|
14555
14655
|
"After you `cdk deploy --outputs-file <file>`, wire those outputs into agentcore.json + .studio/.env.local (default file: agentcore/cognito/cdk-outputs.json). Pure local file I/O \u2014 studio never calls AWS."
|
|
@@ -14608,12 +14708,17 @@ function agentDeployDestination(root) {
|
|
|
14608
14708
|
}
|
|
14609
14709
|
function resolveTarget(opts, root, destination = agentDeployDestination(root)) {
|
|
14610
14710
|
const explicit = opts.runtime ?? opts.target;
|
|
14611
|
-
if (explicit) {
|
|
14612
|
-
return explicit;
|
|
14613
|
-
}
|
|
14614
14711
|
if (destination === "platform") {
|
|
14712
|
+
if (explicit && explicit !== "platform") {
|
|
14713
|
+
printErr(
|
|
14714
|
+
`warning: --runtime=${explicit} ignored \u2014 studio.toml has [deploy].destination = 'platform', which selects the managed deploy path and its own checks. Use --provider bnb|aws to pick where this agent deploys.`
|
|
14715
|
+
);
|
|
14716
|
+
}
|
|
14615
14717
|
return "platform";
|
|
14616
14718
|
}
|
|
14719
|
+
if (explicit) {
|
|
14720
|
+
return explicit;
|
|
14721
|
+
}
|
|
14617
14722
|
return readStackRuntime(root) ?? "agentcore";
|
|
14618
14723
|
}
|
|
14619
14724
|
function validateRuntimeAgainstStack(target, force, root) {
|
|
@@ -14820,6 +14925,12 @@ function writeAgentDeployState(workspaceRoot, arn, record = {}, destination = "s
|
|
|
14820
14925
|
if (scope) {
|
|
14821
14926
|
setEnvVar(envLocalPath16(agentRoot2), "OAUTH_SCOPE", scope);
|
|
14822
14927
|
}
|
|
14928
|
+
syncDescriptorOauthFacts(workspaceRoot, {
|
|
14929
|
+
tokenUrl,
|
|
14930
|
+
scope,
|
|
14931
|
+
discoveryUrl,
|
|
14932
|
+
clientId
|
|
14933
|
+
});
|
|
14823
14934
|
if (persistedPackaging(agentRoot2) === null) {
|
|
14824
14935
|
patchTomlKv(
|
|
14825
14936
|
tomlPath,
|
|
@@ -15085,6 +15196,17 @@ async function refreshLocalDeployDependencies(root) {
|
|
|
15085
15196
|
return 1;
|
|
15086
15197
|
}
|
|
15087
15198
|
}
|
|
15199
|
+
function partialDeployCleanupNote(workspaceRoot) {
|
|
15200
|
+
const project = projectName(workspaceRoot);
|
|
15201
|
+
return [
|
|
15202
|
+
"note: a deploy that fails partway can leave these behind (they are reused by a successful retry, so clean up only if you are giving up):",
|
|
15203
|
+
` - ECR image bnbagent/${project}`,
|
|
15204
|
+
` - Secrets Manager bnbagent/${project}/runtime`,
|
|
15205
|
+
` - Cognito M2M client bnbagent-${project}`,
|
|
15206
|
+
` - IAM role bnbagent-${project}-runtime`,
|
|
15207
|
+
" `bag deploy destroy --provider aws --execute` removes the runtime, secret, and M2M client; add --purge for the ECR repository and log groups. The IAM role is deleted with the runtime it was created for."
|
|
15208
|
+
].join("\n");
|
|
15209
|
+
}
|
|
15088
15210
|
async function cmdAgent(opts, agentcoreArgs) {
|
|
15089
15211
|
let rc = applyProjectRoot(opts.projectRoot);
|
|
15090
15212
|
if (rc !== null) {
|
|
@@ -15296,6 +15418,7 @@ async function cmdAgent(opts, agentcoreArgs) {
|
|
|
15296
15418
|
printErr(
|
|
15297
15419
|
"note: the pinned bnbagent-deploy adapter automatically restores an owned runtime secret that is inside its recovery window. If AWS denies that operation, update the deployer policy to include secretsmanager:RestoreSecret."
|
|
15298
15420
|
);
|
|
15421
|
+
printErr(partialDeployCleanupNote(workspaceRoot));
|
|
15299
15422
|
return code;
|
|
15300
15423
|
}
|
|
15301
15424
|
const record = recordOf2(data);
|
|
@@ -15638,6 +15761,7 @@ function verifyToJson(r) {
|
|
|
15638
15761
|
studio_toml_updated: r.studioTomlUpdated,
|
|
15639
15762
|
runtime: r.runtime,
|
|
15640
15763
|
note: r.note,
|
|
15764
|
+
warning: r.warning,
|
|
15641
15765
|
error: r.error,
|
|
15642
15766
|
exit_code: r.exitCode
|
|
15643
15767
|
};
|
|
@@ -15679,6 +15803,9 @@ function renderVerifyHuman(r, deployment, liveStatus) {
|
|
|
15679
15803
|
if (r.note) {
|
|
15680
15804
|
printOut(`note: ${r.note}`);
|
|
15681
15805
|
}
|
|
15806
|
+
if (r.warning) {
|
|
15807
|
+
printOut(`warning: ${r.warning}`);
|
|
15808
|
+
}
|
|
15682
15809
|
if (r.error) {
|
|
15683
15810
|
printOut(`error: ${r.error}`);
|
|
15684
15811
|
}
|
|
@@ -16026,6 +16153,7 @@ async function cmdFixGitignore(opts) {
|
|
|
16026
16153
|
printOut(`${marker} ${result.name}: ${result.message}`);
|
|
16027
16154
|
return 0;
|
|
16028
16155
|
}
|
|
16156
|
+
var PROVISION_COGNITO_DEPRECATION = "warning: `bag deploy provision-cognito` is deprecated and will be removed.\n `bag deploy` provisions the inbound OAuth user pool and M2M client on its\n own; the pool this CDK app stands up is never used by a deploy, and both\n the stack and its client are billable orphans you have to clean up.\n Run `bag deploy --provider aws` directly instead.";
|
|
16029
16157
|
async function cmdProvisionCognito(opts) {
|
|
16030
16158
|
const rc = applyProjectRoot(opts.projectRoot, false);
|
|
16031
16159
|
if (rc !== null) {
|
|
@@ -16033,6 +16161,7 @@ async function cmdProvisionCognito(opts) {
|
|
|
16033
16161
|
}
|
|
16034
16162
|
const root = resolveProjectRoot2(opts.projectRoot);
|
|
16035
16163
|
const workspaceRoot = deployWorkspaceRoot2(root);
|
|
16164
|
+
printOut(PROVISION_COGNITO_DEPRECATION);
|
|
16036
16165
|
if (opts.wire !== void 0 && opts.wire !== false) {
|
|
16037
16166
|
const outputsFile = typeof opts.wire === "string" && opts.wire ? opts.wire : null;
|
|
16038
16167
|
try {
|
|
@@ -20254,7 +20383,7 @@ function buildProgram() {
|
|
|
20254
20383
|
return program;
|
|
20255
20384
|
}
|
|
20256
20385
|
function cliVersion() {
|
|
20257
|
-
return "0.0.6-alpha.
|
|
20386
|
+
return "0.0.6-alpha.7";
|
|
20258
20387
|
}
|
|
20259
20388
|
|
|
20260
20389
|
// src/cli/updateCheck.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/studio-cli",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.7",
|
|
4
4
|
"description": "The `bag` CLI: scaffold, run, deploy, and monetize a single seller agent on BNB Chain (ERC-8004 identity, ERC-8183 commerce, x402 payments).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"tar": "^7.4.0",
|
|
39
39
|
"viem": "^2.54.0",
|
|
40
40
|
"yaml": "^2.9.0",
|
|
41
|
-
"@bnbagent/studio-runtime": "0.0.6-alpha.
|
|
41
|
+
"@bnbagent/studio-runtime": "0.0.6-alpha.7"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@a2a-js/sdk": "^0.3.14",
|
|
@@ -97,7 +97,7 @@ prices retain the paid merchant flow.
|
|
|
97
97
|
|
|
98
98
|
## CLI groups at a glance
|
|
99
99
|
|
|
100
|
-
`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]` is the primary deploy command; `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, `fix-gitignore
|
|
100
|
+
`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]` is the primary deploy command; `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.4.14`.
|
|
101
101
|
|
|
102
102
|
## Tool surface
|
|
103
103
|
|
|
@@ -189,16 +189,16 @@ ERC-8004/8183 **last** with the deployed AgentCore endpoint:
|
|
|
189
189
|
|
|
190
190
|
```bash
|
|
191
191
|
bag deploy prepare # readiness sweep
|
|
192
|
-
bag deploy provision-cognito # emits the Cognito CDK app you run (cdk deploy); wires discoveryUrl/clientId
|
|
193
192
|
bag deploy --provider aws # ship the Agent to AgentCore
|
|
194
193
|
bag deploy verify --provider aws # delegated status + reconcile ERC-8004 identity
|
|
195
194
|
```
|
|
196
195
|
|
|
197
|
-
Gotcha:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
Gotcha: `bag deploy --provider aws` provisions the Cognito user pool and the
|
|
197
|
+
buyer M2M client itself and prints the token URL, client id, and scope — hand
|
|
198
|
+
those to each buyer (Cognito has no public M2M self-registration; retrieve the
|
|
199
|
+
client secret read-only from the AWS Console). Do not run
|
|
200
|
+
`bag deploy provision-cognito`: it is deprecated and its CDK pool is never used
|
|
201
|
+
by a deploy.
|
|
202
202
|
|
|
203
203
|
Gotcha: `dispute_window` is read from the on-chain policy contract (24h on
|
|
204
204
|
testnet). Buyers can dispute within that window after submit — the Agent can't
|
|
@@ -25,7 +25,7 @@ wallet/LLM/budget ops.
|
|
|
25
25
|
directory (Claude Code: `~/.claude/skills/bnbagent-studio/references/`; Cursor:
|
|
26
26
|
`bnbagent-studio/references/` beside the `.mdc` rules). READ
|
|
27
27
|
the file when the topic comes up — don't answer from memory:
|
|
28
|
-
- `bnbagent-studio-use-aws-agentcore.md` — the delegated AgentCore lifecycle (`bag deploy --provider aws` / `status` / `logs` / `verify` / `destroy
|
|
28
|
+
- `bnbagent-studio-use-aws-agentcore.md` — the delegated AgentCore lifecycle (`bag deploy --provider aws` / `status` / `logs` / `verify` / `destroy`) + AWS prerequisites
|
|
29
29
|
- `bnbagent-studio-use-bnb-trial.md` — GitHub device login, 48h eligibility, staging verification, and the delegated BNB trial lifecycle
|
|
30
30
|
- `bnbagent-studio-using-twak-wallet.md` — `[wallet].kind = "twak"` create / fund / SIWE-bind / container deploy / limitations
|
|
31
31
|
- `bnbagent-studio-extending-signing.md` — `PolicyViolation` / `X402PolicyError` diagnosis + extending the EIP-712 allowlist
|
|
@@ -136,7 +136,6 @@ Returns a rich table of checks across the `app/agent/` sub-project:
|
|
|
136
136
|
| Wallet tBNB balance | 0 tBNB | Faucet: testnet.bnbchain.org/faucet-smart |
|
|
137
137
|
| Wallet U balance | 0 U | Transfer from holder, or ask for sponsor U |
|
|
138
138
|
| 8004 registered | Not registered | Normally registered automatically at `bag deploy verify`. Manual: `bag erc8004 register --endpoint <url>` (only if you need an on-chain identity before deploy). WARN-only in `bag doctor` — it doesn't block local dev. |
|
|
139
|
-
| Cognito authorizer (W9) | External-buyer readiness: `agentcore.json` carries no `authorizerConfiguration` / protocol metadata has placeholder `OAUTH_*` values | WARN-only (does NOT block) — needed to serve **external** buyers, not to deploy. With no authorizer the runtime is IAM/SigV4 owner-only (never anonymous). To open it to buyers: `bag deploy provision-cognito` → `cdk deploy --outputs-file cdk-outputs.json` → `bag deploy provision-cognito --wire`. |
|
|
140
139
|
|
|
141
140
|
WARN-only items don't block; FAIL items do (exit 1).
|
|
142
141
|
|
|
@@ -490,10 +490,10 @@ Local dev (from workspace root <name>/):
|
|
|
490
490
|
# seller's skills). For MCP, use an MCP client.
|
|
491
491
|
|
|
492
492
|
When ready to deploy:
|
|
493
|
-
bag deploy provision-cognito # emit the Cognito CDK app — you run `cdk deploy`,
|
|
494
|
-
# then its discoveryUrl/clientId wire into the OAuth2 authorizer
|
|
495
493
|
bag deploy prepare # readiness sweep
|
|
496
494
|
bag deploy --provider aws # ship the Agent to AgentCore (selected faces);
|
|
495
|
+
# provisions the Cognito pool + buyer M2M client and
|
|
496
|
+
# prints the token URL / client id / scope;
|
|
497
497
|
# keystore injected via Secrets Manager (never in the CodeZip)
|
|
498
498
|
bag deploy verify --provider aws --endpoint <url> # delegated status + reconcile ERC-8004
|
|
499
499
|
|
|
@@ -529,13 +529,12 @@ Edit (from workspace root):
|
|
|
529
529
|
`TWAK_WALLET_PASSWORD` for twak — reconstructed at cold start, never in the
|
|
530
530
|
package; the testnet-only `--secrets-mode envvars` fallback is refused on
|
|
531
531
|
mainnet.
|
|
532
|
-
- **AgentCore seller endpoints are never anonymous.**
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
the scheme and is reachable without a token.
|
|
532
|
+
- **AgentCore seller endpoints are never anonymous.** `bag deploy --provider aws`
|
|
533
|
+
provisions the Cognito OAuth2 pool + buyer M2M client itself and prints the
|
|
534
|
+
token URL / client id / scope to hand to buyers (`bag deploy provision-cognito`
|
|
535
|
+
is deprecated — a deploy uses its own pool regardless). Locally, `bag dev` runs
|
|
536
|
+
without Cognito env, so the card omits the scheme and is reachable without a
|
|
537
|
+
token.
|
|
539
538
|
- **ERC-8183 does NOT require ERC-8004** at the protocol level (commerce contract
|
|
540
539
|
doesn't check the identity registry). Local two-agent dev can run end-to-end
|
|
541
540
|
without ever touching 8004. Use 8004 only when you actually want discoverable
|
|
@@ -160,12 +160,11 @@ Full Pieverse credit decisions live in `funding-pieverse-llm` (project-scope ski
|
|
|
160
160
|
|
|
161
161
|
ERC-8183 / ERC-8004 registration is a **deploy-time** concern: the public
|
|
162
162
|
AgentCore endpoint must exist before you register, so register **last**. The
|
|
163
|
-
agent endpoint has no anonymous mode
|
|
164
|
-
authorizer
|
|
163
|
+
agent endpoint has no anonymous mode; `bag deploy` provisions the Cognito
|
|
164
|
+
OAuth2 authorizer as part of the deploy.
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
167
|
bag deploy prepare # readiness sweep
|
|
168
|
-
bag deploy provision-cognito # emit the Cognito CDK app; run `cdk deploy`, wire discoveryUrl/clientId
|
|
169
168
|
bag deploy --provider aws # ship the agent to AgentCore (selected protocol)
|
|
170
169
|
bag deploy verify --provider aws # delegated status + reconcile ERC-8004 identity
|
|
171
170
|
```
|
|
@@ -178,7 +177,7 @@ asks bnbagent-deploy for live status first, then performs the reconcile.
|
|
|
178
177
|
|
|
179
178
|
**Hard rules**:
|
|
180
179
|
- The endpoint must be **reachable** when registered. For A2A, smoke test the normalized card URL directly, for example `curl <agentcore-invocations-url>/.well-known/agent-card.json` (or `curl <already-registered-card-url>` if the endpoint already includes `/.well-known/agent-card.json`). For MCP, connect an MCP client to the deployed `/mcp` URL. Chain doesn't verify reachability, but buyers will see failures.
|
|
181
|
-
-
|
|
180
|
+
- `bag deploy --provider aws` provisions the Cognito user pool + buyer M2M client and prints the token URL, client id, and scope. Hand those to each buyer (the client secret is retrieved read-only from the AWS Console — studio never stores it). `bag deploy provision-cognito` is deprecated; its CDK pool is never used by a deploy.
|
|
182
181
|
- Price bounds (`min_price`/`max_price`) live with the Agent — it clamps + signs the quote.
|
|
183
182
|
|
|
184
183
|
## Stage 5 — How a SUBMITTED job happens
|
|
@@ -106,7 +106,7 @@ flags); cloud execution is the pinned bnbagent-deploy's job.
|
|
|
106
106
|
| `bag deploy status [--provider aws]` | List every recorded deployment and delegated live state (read-only); `--no-probe` is local-only. |
|
|
107
107
|
| `bag deploy logs [--provider aws] [--follow] [--since 10m]` | Delegate runtime logs to bnbagent-deploy. |
|
|
108
108
|
| `bag deploy destroy [--provider aws]` | Dry-run teardown plan; `--execute` delegates `destroy --yes`; `--purge` also deletes retained ECR/log resources. |
|
|
109
|
-
| `bag deploy provision-cognito [--wire]` |
|
|
109
|
+
| `bag deploy provision-cognito [--wire]` | **Deprecated** (hidden from `--help`). Emits a Cognito CDK app whose pool a deploy never uses. |
|
|
110
110
|
|
|
111
111
|
## Typical workflows
|
|
112
112
|
|
|
@@ -129,21 +129,19 @@ plus a container engine.
|
|
|
129
129
|
> without asking the user first.
|
|
130
130
|
|
|
131
131
|
> 🔒 **Inbound auth is auto-provisioned.** An AgentCore seller endpoint is
|
|
132
|
-
> **never anonymous**.
|
|
133
|
-
>
|
|
134
|
-
>
|
|
135
|
-
>
|
|
132
|
+
> **never anonymous**. The delegated deploy provisions a Cognito inbound OAuth
|
|
133
|
+
> (account pool + per-agent M2M client) so the runtime is token-gated, then
|
|
134
|
+
> writes the live token URL, scope, client id, and discovery URL back into
|
|
135
|
+
> `studio.toml`, `agentcore.json`, and the printed buyer block. Hand those to
|
|
136
|
+
> each buyer; the client secret is retrieved read-only in the AWS Console
|
|
137
|
+
> (Cognito → User pools → App clients → "Show client secret") — never
|
|
138
|
+
> persisted by studio.
|
|
136
139
|
>
|
|
137
|
-
>
|
|
138
|
-
>
|
|
139
|
-
>
|
|
140
|
-
> 2. `bag deploy provision-cognito --wire` reads that local outputs file and
|
|
141
|
-
> patches `agentcore.json`'s `authorizerConfiguration.customJwtAuthorizer` +
|
|
142
|
-
> the card's `OAUTH_TOKEN_URL` / `OAUTH_SCOPE` (no AWS call). The client
|
|
143
|
-
> secret is retrieved read-only in the AWS Console (Cognito → User pools →
|
|
144
|
-
> App clients → "Show client secret") — never persisted by studio.
|
|
140
|
+
> `bag deploy provision-cognito` (the CDK path) is **deprecated**: a deploy
|
|
141
|
+
> provisions and uses its own pool regardless, so the CDK stack is a billable
|
|
142
|
+
> orphan and anything wired from it gets overwritten.
|
|
145
143
|
>
|
|
146
|
-
> Buyers
|
|
144
|
+
> Buyers reach the agent over plain HTTPS + an OAuth2 Bearer (the
|
|
147
145
|
> client-credentials grant) — **no AWS SigV4 / IAM credentials**. Locally,
|
|
148
146
|
> `bag dev` runs without Cognito env, so the card omits the scheme.
|
|
149
147
|
|